mirror of
https://gitee.com/openharmony/arkcompiler_runtime_core
synced 2024-10-07 05:43:39 +00:00
Add arkplatform and static_core
Commit in SIG repository is d4f68dcd4885305251453b0f4d5f986efbf7cb2a Change-Id: I0e2de819f97978468c9dc36c2f5755179f374ed4 Signed-off-by: Artem Udovichenko <artem.udovichenko@huawei.com>
This commit is contained in:
parent
edcdc248b3
commit
d386df8ba4
11
.gitignore
vendored
11
.gitignore
vendored
@ -14,3 +14,14 @@ tags
|
||||
.byebug_history
|
||||
.cache
|
||||
*.swp
|
||||
static_core/extras/*
|
||||
static_core/jenkins-ci
|
||||
static_core/libllvmaot
|
||||
static_core/scripts/*
|
||||
static_core/platforms/*
|
||||
static_core/plugins/accord
|
||||
static_core/plugins/java
|
||||
static_core/plugins/cangjie
|
||||
static_core/plugins/ecmascript
|
||||
static_core/plugins/hz_ecmascript
|
||||
static_core/plugins/tests_java_ecmascript
|
||||
|
24
arkplatform/BUILD.gn
Normal file
24
arkplatform/BUILD.gn
Normal file
@ -0,0 +1,24 @@
|
||||
import("//arkcompiler/runtime_core/ark_config.gni")
|
||||
|
||||
group("arkplatform_packages") {
|
||||
deps = [ ":libarkplatform" ]
|
||||
}
|
||||
|
||||
config("arkplatform_public_config") {
|
||||
include_dirs = [
|
||||
"include",
|
||||
]
|
||||
}
|
||||
|
||||
ohos_shared_library("libarkplatform") {
|
||||
sources = [ "src/arkplatform.cpp" ]
|
||||
include_dirs = [
|
||||
"$ark_root/arkplatform",
|
||||
"//base/hiviewdfx/hilog/interfaces/native/innerkits/include"
|
||||
]
|
||||
|
||||
output_extension = "so"
|
||||
part_name = "runtime_core"
|
||||
subsystem_name = "arkcompiler"
|
||||
external_deps = [ "hilog:libhilog" ]
|
||||
}
|
10
arkplatform/include/arkplatform.h
Normal file
10
arkplatform/include/arkplatform.h
Normal file
@ -0,0 +1,10 @@
|
||||
#include <string>
|
||||
|
||||
namespace arkplatform {
|
||||
|
||||
class ArkPlatform {
|
||||
public:
|
||||
static void Create(const std::string& s);
|
||||
};
|
||||
|
||||
}
|
14
arkplatform/src/arkplatform.cpp
Normal file
14
arkplatform/src/arkplatform.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include <hilog/log.h>
|
||||
|
||||
#include "include/arkplatform.h"
|
||||
|
||||
namespace arkplatform {
|
||||
|
||||
void ArkPlatform::Create(const std::string& s) {
|
||||
constexpr static unsigned int ARK_DOMAIN = 0xD003F00;
|
||||
constexpr static auto TAG = "ArkPlatform";
|
||||
constexpr static OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, ARK_DOMAIN, TAG};
|
||||
OHOS::HiviewDFX::HiLog::Info(LABEL, "%{public}s", "UDAV: Hello from arkplatform");
|
||||
}
|
||||
|
||||
}
|
30
bundle.json
30
bundle.json
@ -22,10 +22,15 @@
|
||||
"ram": "",
|
||||
"deps": {
|
||||
"components": [
|
||||
"hilog"
|
||||
"hilog",
|
||||
"napi"
|
||||
],
|
||||
"third_party": [
|
||||
"bounds_checking_function"
|
||||
"bounds_checking_function",
|
||||
"icu",
|
||||
"musl",
|
||||
"vixl",
|
||||
"zlib"
|
||||
]
|
||||
},
|
||||
"build": {
|
||||
@ -95,6 +100,27 @@
|
||||
"header_files": [],
|
||||
"header_base": "//arkcompiler/runtime_core/compiler"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "//arkcompiler/runtime_core/arkplatform:libarkplatform",
|
||||
"header": {
|
||||
"header_files": [],
|
||||
"header_base": "//arkcompiler/runtime_core/arkplatform/include"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "//arkcompiler/runtime_core/static_core/runtime:libarkruntime",
|
||||
"header": {
|
||||
"header_files": [],
|
||||
"header_base": "//arkcompiler/runtime_core/static_core/runtime/include"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "//arkcompiler/runtime_core/static_core/plugins/ets/runtime/interop_js:ets_interop_js_napi",
|
||||
"header": {
|
||||
"header_files": [],
|
||||
"header_base": "//arkcompiler/runtime_core/static_core/plugins/ets/runtime/interop_js"
|
||||
}
|
||||
}
|
||||
],
|
||||
"test": [
|
||||
|
114
static_core/.clang-format
Normal file
114
static_core/.clang-format
Normal file
@ -0,0 +1,114 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: true
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 120
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Right
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
...
|
||||
|
139
static_core/.clang-tidy
Normal file
139
static_core/.clang-tidy
Normal file
@ -0,0 +1,139 @@
|
||||
---
|
||||
WarningsAsErrors: "*"
|
||||
AnalyzeTemporaryDtors: false
|
||||
User: user
|
||||
CheckOptions:
|
||||
- key: google-readability-braces-around-statements.ShortStatementLines
|
||||
value: "1"
|
||||
- key: google-readability-function-size.StatementThreshold
|
||||
value: "800"
|
||||
- key: google-readability-namespace-comments.ShortNamespaceLines
|
||||
value: "10"
|
||||
- key: google-readability-namespace-comments.SpacesBeforeComments
|
||||
value: "2"
|
||||
- key: modernize-loop-convert.MaxCopySize
|
||||
value: "16"
|
||||
- key: modernize-loop-convert.MinConfidence
|
||||
value: reasonable
|
||||
- key: modernize-loop-convert.NamingStyle
|
||||
value: CamelCase
|
||||
- key: modernize-pass-by-value.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-replace-auto-ptr.IncludeStyle
|
||||
value: llvm
|
||||
- key: modernize-use-nullptr.NullMacros
|
||||
value: "NULL"
|
||||
- key: readability-function-size.LineThreshold
|
||||
value: 200
|
||||
- key: readability-magic-numbers.IgnoredIntegerValues
|
||||
value: "1;2;3;4;5;6;7;8"
|
||||
- key: readability-identifier-naming.AbstractClassCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.ClassCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.ClassConstantCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.ClassMemberCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.ClassMemberSuffix
|
||||
value: _
|
||||
- key: readability-identifier-naming.ClassMethodCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.ConstantCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.ConstantMemberCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.ConstantMemberSuffix
|
||||
value: _
|
||||
- key: readability-identifier-naming.ConstantParameterCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.ConstantPointerParameterCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.ConstexprFunctionCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.ConstexprMethodCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.ConstexprVariableCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.EnumCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.EnumConstantCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.FunctionCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.GlobalConstantCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.GlobalConstantPointerCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.GlobalFunctionCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.GlobalPointerCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.GlobalVariableCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.InlineNamespaceCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.LocalConstantCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.LocalConstantPointerCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.LocalPointerCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.LocalVariableCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.MemberCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.MemberSuffix
|
||||
value: _
|
||||
- key: readability-identifier-naming.MethodCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.NamespaceCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.ParameterCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.ParameterPackCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.PointerParameterCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.PrivateMemberCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.PrivateMemberSuffix
|
||||
value: _
|
||||
- key: readability-identifier-naming.PrivateMethodCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.ProtectedMemberCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.ProtectedMemberSuffix
|
||||
value: _
|
||||
- key: readability-identifier-naming.ProtectedMethodCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.PublicMemberCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.PublicMemberSuffix
|
||||
value: ""
|
||||
- key: readability-identifier-naming.PublicMethodCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.StaticConstantCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.StaticVariableCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.StructCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.TemplateParameterCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.TemplateTemplateParameterCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.TypeAliasCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.TypedefCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.TypeTemplateParameterCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.UnionCase
|
||||
value: CamelCase
|
||||
- key: readability-identifier-naming.ValueTemplateParameterCase
|
||||
value: UPPER_CASE
|
||||
- key: readability-identifier-naming.VariableCase
|
||||
value: lower_case
|
||||
- key: readability-identifier-naming.VirtualMethodCase
|
||||
value: CamelCase
|
23
static_core/.gn
Normal file
23
static_core/.gn
Normal file
@ -0,0 +1,23 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# This is an entry point for Ark standalone build with gn.
|
||||
# It is ignored when Ark is built as a part of OpenHarmony source tree.
|
||||
|
||||
buildconfig = "//build/config/BUILDCONFIG.gn"
|
||||
|
||||
secondary_source = "//gn"
|
||||
script_executable = "/usr/bin/env"
|
||||
|
||||
exec_script("//scripts/install-third-party")
|
||||
exec_script("//gn/build/fixup-third-party.sh")
|
189
static_core/AUTHORS
Normal file
189
static_core/AUTHORS
Normal file
@ -0,0 +1,189 @@
|
||||
Aleksandr Emelenko
|
||||
Aleksandr Latikov
|
||||
Aleksandr Lovkov
|
||||
Aleksandr Popov
|
||||
Aleksandr Semenov
|
||||
Aleksandr Tokmakov
|
||||
Aleksandr Urakov
|
||||
Aleksandr Vorobyev
|
||||
Alexander Polyakov
|
||||
Aleksei Akmaev
|
||||
Aleksei Grebenkin
|
||||
Aleksei Nedoria
|
||||
Aleksei Sidorov
|
||||
Alexey Biryukov
|
||||
Alexey Kanatov
|
||||
Alexey Romanov
|
||||
Alexey Volokhov
|
||||
Alina Chernikova
|
||||
Alina Kropacheva
|
||||
An Guanglin
|
||||
Andrey Efremov
|
||||
Anna Antipina
|
||||
Anton Makarenko
|
||||
Anton Romanov
|
||||
Anton Soldatov
|
||||
Artem Udovichenko
|
||||
Chen Mudan
|
||||
Chen Qingyuan
|
||||
Chen Qiuyao
|
||||
Chen Tingwei
|
||||
Chen Yilong
|
||||
Csaba Osztrogonac
|
||||
Csaba Repasi
|
||||
Cui Guihua
|
||||
Dai Huina
|
||||
Daniel Batiz
|
||||
Daniel Batyai
|
||||
Daniil Kochergin
|
||||
Daniil Kofanov
|
||||
Denis Krylov
|
||||
Denis Silakov
|
||||
Denis Slynko
|
||||
Denis Tomashev
|
||||
Denis Zakharov
|
||||
Denis Zavedeev
|
||||
Ding Ding
|
||||
Ding Shenke
|
||||
Ding Wen
|
||||
Dmitrii Trubenkov
|
||||
Dmitry Bubnov
|
||||
Dmitry Buzmakov
|
||||
Dmitry Kovalenko
|
||||
Dmitry Nechitaev
|
||||
Dmitry Popov
|
||||
Dmitry Solomennikov
|
||||
Dong Kaixing
|
||||
Du Qing
|
||||
Evgenii Kudriashov
|
||||
Evgeny Erokhin
|
||||
Evgeny Gavrin
|
||||
Evgeny Gerlits
|
||||
Evgeny Sharygin
|
||||
Feng Feng
|
||||
Gan Lan
|
||||
Gao Lei
|
||||
Ge Tingke
|
||||
Georgy Bronnikov
|
||||
Gong Junsong
|
||||
Guo Bingbing
|
||||
Hao Tuo
|
||||
Hong Tao
|
||||
Hu Feng
|
||||
Hu Xiaowei
|
||||
Huang Feijie
|
||||
Huang Haitao
|
||||
Huang Huijin
|
||||
Huang Yu
|
||||
Igor Gorban
|
||||
Igor Petrov
|
||||
Ilya Makarov
|
||||
Ilya Trubachev
|
||||
Ilya Tyulyandin
|
||||
Ivan Vagin
|
||||
Ivan Burimskii
|
||||
Ivan Trubachev
|
||||
Ivan Tyulyandin
|
||||
Ji Andong
|
||||
Jiang Han
|
||||
Jiang Suqin
|
||||
Kirill Galitskiy
|
||||
Kira Prokopenko
|
||||
Konstantin Baladurin
|
||||
Konstantin Nazarov
|
||||
Laszlo Lango
|
||||
Leonid Dyachkov
|
||||
Leonid Skvortsov
|
||||
Li Chenshuai
|
||||
Li Wentao
|
||||
Li Yiming
|
||||
Li Yongbiao
|
||||
Lin Xiang
|
||||
Liu Chiming
|
||||
Liu Jialiang
|
||||
Liu Xin
|
||||
Lu Kai
|
||||
Luo Chuhao
|
||||
Maria Filippova
|
||||
Mark Gonopolskiy
|
||||
Martin Negyorku
|
||||
Maxim Bolshov
|
||||
Maxim Morozov
|
||||
Maxim Tsyngaev
|
||||
Maxim Zimnyukov
|
||||
Mikhail Aksenov
|
||||
Mikhail Chernov
|
||||
Mikhail Kaskov
|
||||
Mikhail Redkin
|
||||
Mikhail Sherstennikov
|
||||
Mikita Strizhak
|
||||
Nikita Kharitonov
|
||||
Nikita Sizov
|
||||
Pan Zhenyu
|
||||
Pang Desong
|
||||
Pavel Andrianov
|
||||
Pavel Ishin
|
||||
Pavel Kosov
|
||||
Pei Jiajun
|
||||
Peng Biao
|
||||
Petr Shumilov
|
||||
Qiu Yu
|
||||
Robert Fancsik
|
||||
Robert Sipka
|
||||
Roland Takacs
|
||||
Roman Baev
|
||||
Roman Sannikov
|
||||
Roman Zhuykov
|
||||
Sergei Shadrin
|
||||
Sergey Chernykh
|
||||
Sergey Goldenberg
|
||||
Sergey Nikitin
|
||||
Stepan Dyatkovskiy
|
||||
Su Chongwei
|
||||
Sun Yuanlei
|
||||
Sun Zhe
|
||||
Tang Jiajun
|
||||
Vadim Mutilin
|
||||
Vadim Sofin
|
||||
Vasil Dyadov
|
||||
Viktor Foteev
|
||||
Viktor Kutuzov
|
||||
Vitalii Mordan
|
||||
Vladimir Kuznetsov
|
||||
Vladimir Popov
|
||||
Vladimir Rubanov
|
||||
Vladislav Ivanishin
|
||||
Vsevolod Pukhov
|
||||
Vyacheslav Cherkashin
|
||||
Wan Yanglan
|
||||
Wang Deyu
|
||||
Wang Gang
|
||||
Wang Shangling
|
||||
Wang Xin
|
||||
Wang Yantian
|
||||
Wang Yaofeng
|
||||
Wang Zhaoyong
|
||||
Weng Changcheng
|
||||
Wu Pengyong
|
||||
Wu Zhefeng
|
||||
Xian Yuqiang
|
||||
Xiong Luo
|
||||
Xu Cheng
|
||||
Xu Jie
|
||||
Xu Liang
|
||||
Yan Churkin
|
||||
Yang Yang
|
||||
Yao Jian
|
||||
Ye Xiangrun
|
||||
Yi Honglie
|
||||
Yin Chuang
|
||||
Ying Guofeng
|
||||
Yu Jianchao
|
||||
Yury Nikitin
|
||||
Zhang Quan
|
||||
Zhang Rengao
|
||||
Zhang Yukun
|
||||
Zhao Gaoyi
|
||||
Zheng Jiahuan
|
||||
Zhou Cong
|
||||
Zhou Mingsong
|
318
static_core/BUILD.gn
Normal file
318
static_core/BUILD.gn
Normal file
@ -0,0 +1,318 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//arkcompiler/runtime_core/static_core/ark_config.gni")
|
||||
import("//build/ohos.gni")
|
||||
import("$ark_root/plugins/plugins.gni")
|
||||
|
||||
group("ark_packages") {
|
||||
deps = plugin_ark_packages
|
||||
if (host_os != "mac") {
|
||||
deps += [
|
||||
"$ark_root/compiler:libarktscompiler",
|
||||
"$ark_root/compiler/aot:libarkaotmanager",
|
||||
"$ark_root/compiler/optimizer/code_generator:libarkencoder",
|
||||
"$ark_root/libpandabase:libarktsbase",
|
||||
"$ark_root/libpandafile:libarktsfile",
|
||||
"$ark_root/libpandafile/external:libarkfileExt",
|
||||
"$ark_root/libpandafile/external:libarksupport",
|
||||
"$ark_root/libziparchive:libarktsziparchive",
|
||||
"$ark_root/panda:arkts_bin",
|
||||
"$ark_root/runtime:libarkruntime",
|
||||
"$ark_root/runtime/tooling/inspector:libarkinspector",
|
||||
"$ark_root/verification/verifier:verifier.config",
|
||||
"$ark_root/verification/verifier:verifier_bin",
|
||||
]
|
||||
# TODO: don't exclude these targets from OHOS build
|
||||
if (ark_standalone_build) {
|
||||
deps += [
|
||||
"$ark_root/compiler/tools/paoc:ark_aot",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
group("ark_host_linux_tools_packages") {
|
||||
deps = plugin_ark_host_linux_tools_packages
|
||||
if (host_os != "mac" && current_cpu != "arm") {
|
||||
deps += [
|
||||
"$ark_root/assembler:arkts_asm(${host_toolchain})",
|
||||
"$ark_root/compiler:libarktscompiler(${host_toolchain})",
|
||||
"$ark_root/compiler/aot:libarkaotmanager(${host_toolchain})",
|
||||
"$ark_root/compiler/optimizer/code_generator:libarkencoder(${host_toolchain})",
|
||||
"$ark_root/libpandabase:libarktsbase(${host_toolchain})",
|
||||
"$ark_root/libpandafile:libarktsfile(${host_toolchain})",
|
||||
"$ark_root/libpandafile/external:libarkfileExt(${host_toolchain})",
|
||||
"$ark_root/libpandafile/external:libarksupport(${host_toolchain})",
|
||||
"$ark_root/libziparchive:libarktsziparchive(${host_toolchain})",
|
||||
"$ark_root/panda:arkts_bin(${host_toolchain})",
|
||||
"$ark_root/runtime:libarkruntime(${host_toolchain})",
|
||||
]
|
||||
# TODO: don't exclude these targets from OHOS build
|
||||
if (ark_standalone_build) {
|
||||
deps += [
|
||||
"$ark_root/compiler/tools/paoc:ark_aot(${host_toolchain})",
|
||||
"$ark_root/compiler/tools/aotdump:ark_aotdump(${host_toolchain})",
|
||||
"$ark_root/disassembler:ark_disasm(${host_toolchain})",
|
||||
"$ark_root/static_linker:ark_link(${host_toolchain})",
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
group("ark_host_windows_tools_packages") {
|
||||
deps = plugin_ark_host_windows_tools_packages
|
||||
if (host_os != "mac" && current_cpu != "arm" && !ark_standalone_build) {
|
||||
deps += [
|
||||
"$ark_root/assembler:arkts_asm(//build/toolchain/mingw:mingw_x86_64)",
|
||||
"$ark_root/disassembler:ark_disasm(//build/toolchain/mingw:mingw_x86_64)",
|
||||
"$ark_root/static_linker:ark_link(//build/toolchain/mingw:mingw_x86_64)",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
group("ark_host_mac_tools_packages") {
|
||||
deps = plugin_ark_host_mac_tools_packages
|
||||
if (host_os == "mac") {
|
||||
deps += [
|
||||
"$ark_root/assembler:arkts_asm(//build/toolchain/mac:clang_x64)",
|
||||
"$ark_root/disassembler:ark_disasm(//build/toolchain/mac:clang_x64)",
|
||||
"$ark_root/static_linker:ark_link(//build/toolchain/mac:clang_x64)",
|
||||
"$ark_root/libpandabase:libarktsbase(//build/toolchain/mac:clang_x64)",
|
||||
"$ark_root/libpandafile:libarktsfile(//build/toolchain/mac:clang_x64)",
|
||||
"$ark_root/libziparchive:libarktsziparchive(//build/toolchain/mac:clang_x64)",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
group("ark_host_tests") {
|
||||
testonly = true
|
||||
deps = []
|
||||
if (defined(extras)) {
|
||||
foreach(ext, extras) {
|
||||
deps += [ "${ext}:host_tests" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Common config for ark source
|
||||
config("ark_config") {
|
||||
if (!ark_standalone_build) {
|
||||
visibility = [
|
||||
"./*",
|
||||
"$ark_third_party_root/asmjit:*",
|
||||
"$ark_third_party_root/vixl:*"
|
||||
]
|
||||
}
|
||||
|
||||
# In GN build we just create merged files, without any content. Because no languages are involved in GN build.
|
||||
if (current_toolchain == default_toolchain) {
|
||||
generated_file("create_pipeline") { outputs = ["$target_gen_dir/plugins/create_pipeline.h"] contents = "" }
|
||||
generated_file("create_pipeline_includes") { outputs = ["$target_gen_dir/plugins/create_pipeline_includes.h"] contents = "" }
|
||||
|
||||
generated_file("clear_profile") { outputs = ["$target_gen_dir/plugins/clear_profile.h"] contents = "" }
|
||||
generated_file("destroy_profile") { outputs = ["$target_gen_dir/plugins/destroy_profile.h"] contents = "" }
|
||||
generated_file("dump_profile") { outputs = ["$target_gen_dir/plugins/dump_profile.h"] contents = "" }
|
||||
generated_file("find_method_in_profile") { outputs = ["$target_gen_dir/plugins/find_method_in_profile.h"] contents = "" }
|
||||
generated_file("profiling_includes_disasm") { outputs = ["$target_gen_dir/plugins/profiling_includes_disasm.h"] contents = "" }
|
||||
generated_file("profiling_includes") { outputs = ["$target_gen_dir/plugins/profiling_includes.h"] contents = "" }
|
||||
generated_file("read_profile") { outputs = ["$target_gen_dir/plugins/read_profile.h"] contents = "" }
|
||||
}
|
||||
|
||||
include_dirs = [
|
||||
"$ark_root",
|
||||
get_label_info(":create_pipeline(${default_toolchain})", "target_gen_dir")
|
||||
]
|
||||
defines = [ "PANDA_TARGET_MOBILE_WITH_MANAGED_LIBS=1" ]
|
||||
if (is_llvmaot) {
|
||||
defines += [
|
||||
"PANDA_LLVMAOT",
|
||||
"PANDA_LLVMAOT_IR_INLINING",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_ohos && is_standard_system) {
|
||||
defines += [ "PANDA_TARGET_OHOS" ]
|
||||
include_dirs += [
|
||||
"//base/hiviewdfx/hilog/interfaces/innerkits/include"
|
||||
]
|
||||
}
|
||||
|
||||
if (is_linux) {
|
||||
defines += [
|
||||
"PANDA_TARGET_UNIX",
|
||||
"PANDA_TARGET_LINUX",
|
||||
"PANDA_WITH_BYTECODE_OPTIMIZER",
|
||||
"PANDA_WITH_COMPILER",
|
||||
]
|
||||
if (!is_asan) {
|
||||
defines += [ "PANDA_USE_FUTEX" ]
|
||||
}
|
||||
} else if (is_mingw) {
|
||||
defines += [
|
||||
"PANDA_TARGET_WINDOWS",
|
||||
"PANDA_WITH_BYTECODE_OPTIMIZER",
|
||||
"PANDA_WITH_COMPILER",
|
||||
"_CRTBLD",
|
||||
"__LIBMSVCRT__",
|
||||
]
|
||||
} else if (is_mac) {
|
||||
defines += [
|
||||
"PANDA_TARGET_UNIX",
|
||||
"PANDA_TARGET_MACOS",
|
||||
"PANDA_WITH_BYTECODE_OPTIMIZER",
|
||||
"PANDA_WITH_COMPILER",
|
||||
|
||||
# "PANDA_USE_FUTEX",
|
||||
]
|
||||
} else if (is_mob) {
|
||||
defines += [
|
||||
"PANDA_TARGET_UNIX",
|
||||
"PANDA_USE_FUTEX",
|
||||
"PANDA_TARGET_MOBILE",
|
||||
"PANDA_TARGET_MOBILE_WITH_NATIVE_LIBS",
|
||||
]
|
||||
} else if (is_ohos) {
|
||||
defines += [
|
||||
# TODO: use PANDA_TARGET_OHOS instead of PANDA_TARGET_UNIX
|
||||
"PANDA_TARGET_UNIX",
|
||||
"PANDA_USE_FUTEX",
|
||||
]
|
||||
} else {
|
||||
defines += [
|
||||
"PANDA_TARGET_UNIX",
|
||||
"PANDA_USE_FUTEX",
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
if (!is_debug) {
|
||||
defines += [ "NDEBUG" ]
|
||||
}
|
||||
|
||||
cflags_cc = [
|
||||
"-std=c++17",
|
||||
"-pedantic",
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Werror",
|
||||
"-fno-rtti",
|
||||
"-fno-exceptions",
|
||||
"-Wno-invalid-offsetof",
|
||||
|
||||
"-Wno-gnu-statement-expression",
|
||||
"-Wno-unused-parameter",
|
||||
"-Wno-unused-result",
|
||||
]
|
||||
|
||||
if (ark_standalone_build) {
|
||||
cflags_cc += [ "-Wno-bitwise-instead-of-logical" ]
|
||||
}
|
||||
|
||||
if (!is_mac && use_pbqp) {
|
||||
cflags_cc += [
|
||||
# PBQP regalloc
|
||||
"-mllvm",
|
||||
"-regalloc=pbqp",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_debug) {
|
||||
cflags_cc += [
|
||||
"-Og",
|
||||
"-ggdb3",
|
||||
"-gdwarf-4",
|
||||
]
|
||||
}
|
||||
|
||||
if (is_asan) {
|
||||
cflags_cc += [
|
||||
"-fsanitize=address",
|
||||
"-g",
|
||||
]
|
||||
defines += [ "__SANITIZE_ADDRESS__" ]
|
||||
print("ASAN is enabled")
|
||||
}
|
||||
|
||||
if (enable_relayout_profile) {
|
||||
defines += [ "PANDA_ENABLE_RELAYOUT_PROFILE" ]
|
||||
}
|
||||
|
||||
configs = plugin_ark_configs
|
||||
|
||||
if (current_cpu == "arm") {
|
||||
cflags_cc += [
|
||||
"-march=armv7-a",
|
||||
"-mfloat-abi=${arm_float_abi}",
|
||||
"-marm",
|
||||
"-mfpu=vfp",
|
||||
]
|
||||
|
||||
if (arm_float_abi == "soft") {
|
||||
defines += [ "PANDA_TARGET_ARM32_ABI_SOFT=1" ]
|
||||
} else if (arm_float_abi == "softfp") {
|
||||
defines += [ "PANDA_TARGET_ARM32_ABI_SOFTFP=1" ]
|
||||
} else if (arm_float_abi == "hard") {
|
||||
defines += [ "PANDA_TARGET_ARM32_ABI_HARD=1" ]
|
||||
}
|
||||
|
||||
defines += [
|
||||
"PANDA_TARGET_32",
|
||||
"PANDA_TARGET_ARM32"
|
||||
]
|
||||
} else if (current_cpu == "arm64") {
|
||||
defines += [
|
||||
"PANDA_TARGET_ARM64",
|
||||
"PANDA_TARGET_64",
|
||||
"PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES",
|
||||
"PANDA_USE_32_BIT_POINTER",
|
||||
]
|
||||
} else if (current_cpu == "x86") {
|
||||
defines += [ "PANDA_TARGET_X86" ]
|
||||
} else if (current_cpu == "amd64" || current_cpu == "x64" ||
|
||||
current_cpu == "x86_64") {
|
||||
defines += [
|
||||
"PANDA_TARGET_64",
|
||||
"PANDA_TARGET_AMD64",
|
||||
"PANDA_USE_32_BIT_POINTER",
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
concat_yamls("concat_plugins_yamls") {
|
||||
output_file = "$ark_plugin_options_yaml"
|
||||
default_file = "$ark_root/templates/plugin_options.yaml"
|
||||
add_yamls = plugin_option_yamls
|
||||
}
|
||||
|
||||
concat_yamls("concat_entrypoints_yamls") {
|
||||
output_file = "$target_gen_dir/runtime/entrypoints.yaml"
|
||||
default_file = "$ark_root/runtime/entrypoints/entrypoints.yaml"
|
||||
add_yamls = plugin_entrypoints_yamls
|
||||
}
|
||||
|
||||
concat_yamls("concat_inst_templates_yamls") {
|
||||
output_file = "$target_gen_dir/compiler/generated/inst_templates.yaml"
|
||||
default_file = "$ark_root/compiler/optimizer/ir_builder/inst_templates.yaml"
|
||||
add_yamls = plugin_inst_templates_yamls
|
||||
}
|
||||
|
||||
merge_yamls("merge_runtime_options_yamls") {
|
||||
output_file = "$target_gen_dir/runtime_options.yaml"
|
||||
add_yamls = ["$ark_root/runtime/options.yaml"] + plugin_runtime_options_yamls
|
||||
}
|
||||
|
||||
merge_yamls("merge_compiler_options_yamls") {
|
||||
output_file = "$target_gen_dir/compiler/generated/compiler_options.yaml"
|
||||
add_yamls = ["$ark_root/compiler/compiler.yaml"] + plugin_compiler_options_yamls
|
||||
}
|
396
static_core/CMakeLists.txt
Normal file
396
static_core/CMakeLists.txt
Normal file
@ -0,0 +1,396 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||
project(PANDA NONE)
|
||||
|
||||
# Add our custom configuration types to
|
||||
# multi-configuration generators (i.e. Visual Studio):
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
list(APPEND CMAKE_CONFIGURATION_TYPES "FastVerify" "DebugDetailed")
|
||||
list(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES}
|
||||
CACHE STRING "CMake configuration types" FORCE)
|
||||
endif()
|
||||
|
||||
enable_language(CXX)
|
||||
|
||||
# NB! For God's sake do not touch the command below.
|
||||
# See https://gitlab.kitware.com/cmake/cmake/issues/16588.
|
||||
# and https://clang.llvm.org/docs/JSONCompilationDatabase.html
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
|
||||
# ----- Default flags ----------------------------------------------------------
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
# ----- Global variables -------------------------------------------------------
|
||||
# Please don't use CMAKE_SOURCE_DIR and CMAKE_BINARY_DIR to allow building
|
||||
# Panda as a cmake subdirectory. You can use the following variables if you
|
||||
# need to refer the Panda root directories
|
||||
set(PANDA_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(PANDA_BINARY_ROOT ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(PANDA_THIRD_PARTY_SOURCES_DIR ${PANDA_ROOT}/third_party)
|
||||
set(PANDA_THIRD_PARTY_CONFIG_DIR ${PANDA_ROOT}/cmake/third_party)
|
||||
|
||||
# List for accumulation of all core gtests binary paths.
|
||||
# It's used by CI to archive these binaries into a single artifact
|
||||
# and send it to second stage where unit tests will use them.
|
||||
set_property(GLOBAL PROPERTY stash_list "")
|
||||
|
||||
# ----- Policies ---------------------------------------------------------------
|
||||
# Allows the target_link_libraries() command to be called from any directory
|
||||
# to add link dependencies and link interface libraries to targets created in
|
||||
# other directories
|
||||
if(POLICY CMP0079)
|
||||
cmake_policy(SET CMP0079 NEW)
|
||||
endif()
|
||||
|
||||
# ----- Platform definitions ---------------------------------------------------
|
||||
include(cmake/Definitions.cmake)
|
||||
|
||||
if (NOT "${CMAKE_BUILD_TYPE}" MATCHES "Release" AND NOT PANDA_TARGET_WINDOWS)
|
||||
# Needed for stacktrace printing
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -rdynamic")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -Wextra -Werror -Wshadow")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions")
|
||||
|
||||
include(cmake/toolchain/coverage/unit_tests_lcov.cmake)
|
||||
|
||||
if(ENABLE_UNIT_TESTS_FULL_COVERAGE)
|
||||
add_custom_target(coverage_full DEPENDS cts-assembly tests benchmarks)
|
||||
collect_coverage_for_target(TARGET_NAME coverage_full)
|
||||
else()
|
||||
message(STATUS "Full coverage will not be calculated (may be enabled by -DENABLE_UNIT_TESTS_FULL_COVERAGE=true ).")
|
||||
endif(ENABLE_UNIT_TESTS_FULL_COVERAGE)
|
||||
|
||||
if(PANDA_TARGET_MACOS)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.13")
|
||||
endif()
|
||||
|
||||
set(PANDA_PGO_PROFGEN_PATH "/data/local/tmp")
|
||||
|
||||
if (PANDA_TARGET_MOBILE AND (PANDA_TARGET_ARM64 OR PANDA_TARGET_ARM32))
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=lld")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld")
|
||||
endif()
|
||||
|
||||
if (PANDA_PGO_INSTRUMENT)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-generate=${PANDA_PGO_PROFGEN_PATH}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-generate=${PANDA_PGO_PROFGEN_PATH}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-generate=${PANDA_PGO_PROFGEN_PATH}")
|
||||
endif()
|
||||
|
||||
if (PANDA_PGO_OPTIMIZE)
|
||||
if (NOT PANDA_PGO_PROFILE_DATA)
|
||||
message(FATAL_ERROR "PANDA_PGO_PROFILE_DATA is not set")
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-use=${PANDA_PGO_PROFILE_DATA}")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-use=${PANDA_PGO_PROFILE_DATA}")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-use=${PANDA_PGO_PROFILE_DATA}")
|
||||
endif()
|
||||
|
||||
if (PANDA_ENABLE_LTO)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=thin")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -flto=thin")
|
||||
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto=thin")
|
||||
endif()
|
||||
|
||||
if (PANDA_LLVM_REGALLOC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -regalloc=${PANDA_LLVM_REGALLOC}")
|
||||
endif()
|
||||
|
||||
if ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
|
||||
add_compile_options(-O2 -ggdb3 -fno-omit-frame-pointer)
|
||||
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "FastVerify")
|
||||
add_compile_options(-O2 -ggdb3 -fno-omit-frame-pointer)
|
||||
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "DebugDetailed")
|
||||
add_compile_options(-Og -ggdb3 -fno-omit-frame-pointer)
|
||||
endif()
|
||||
|
||||
if (PANDA_THREAD_SAFETY)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wthread-safety")
|
||||
endif()
|
||||
|
||||
include(cmake/RegisterPlugins.cmake)
|
||||
|
||||
panda_promote_to_definitions(
|
||||
PANDA_ENABLE_RELAYOUT_PROFILE
|
||||
)
|
||||
|
||||
# ----- Deliverable executables and libraries ----------------------------------
|
||||
# Please override with per-target properties if your artifact should reside
|
||||
# elsewhere, like this:
|
||||
# set_target_properties(... PROPERTIES RUNTIME_OUTPUT_DIRECTORY ...)
|
||||
# Applicable for tests and all "internal" artifacts.
|
||||
if(NOT HOST_TOOLS)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PANDA_BINARY_ROOT}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PANDA_BINARY_ROOT}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PANDA_BINARY_ROOT}/bin)
|
||||
endif()
|
||||
|
||||
|
||||
if (PANDA_LLVMAOT AND NOT EXISTS "${PANDA_ROOT}/libllvmaot")
|
||||
message(FATAL_ERROR "PANDA_LLVMAOT is ${PANDA_LLVMAOT}, but the libllvmaot dir does not exist")
|
||||
endif()
|
||||
|
||||
# ----- Alias for source generating targets ------------------------------------
|
||||
add_custom_target(panda_gen_files COMMENT "Generate all sources")
|
||||
|
||||
# ----- Panda CMake functions --------------------------------------------------
|
||||
include(cmake/PandaCmakeFunctions.cmake)
|
||||
|
||||
if (PANDA_LLVMAOT)
|
||||
# ----- Enable LLVM AOT compiler -------------------------------------------
|
||||
include(libllvmaot/cmake/LLVM.cmake)
|
||||
|
||||
# ----- Enable LLVM Inline modules -----------------------------------------
|
||||
include(libllvmaot/cmake/LLVMInlineModules.cmake)
|
||||
endif ()
|
||||
|
||||
# ----- Bootstrapping (for parts of platform written in managed code ) ---------
|
||||
include(cmake/HostTools.cmake)
|
||||
|
||||
if (PANDA_ENABLE_CCACHE)
|
||||
# ----- Enable CCache ----------------------------------------------------------
|
||||
include(cmake/PandaCCache.cmake)
|
||||
|
||||
# ----- Enable SCCache ---------------------------------------------------------
|
||||
include(cmake/PandaSCCache.cmake)
|
||||
endif()
|
||||
|
||||
# ----- Documentation generation -----------------------------------------------
|
||||
include(cmake/Doxygen.cmake)
|
||||
|
||||
# ----- Code analysis and style ------------------------------------------------
|
||||
include(cmake/ClangTidy.cmake)
|
||||
include(cmake/CodeStyle.cmake)
|
||||
|
||||
# ----- Sanitizers testing -----------------------------------------------------
|
||||
include(cmake/Sanitizers.cmake)
|
||||
|
||||
# ----- Enable testing ---------------------------------------------------------
|
||||
|
||||
# Umbrella target for testing:
|
||||
add_custom_target(tests COMMENT "Running all test suites")
|
||||
|
||||
define_property(TARGET
|
||||
PROPERTY first-level-tests-dependency
|
||||
BRIEF_DOCS "Whether the target is a first-level dependency of tests"
|
||||
FULL_DOCS "Whether the target is a first-level dependency of tests")
|
||||
|
||||
add_custom_target(core_tests COMMENT "Running core test suites")
|
||||
|
||||
# NB! ADDING THIS PROPERTY IS ALLOWED ONLY IN SPECIAL CASES. DO NOT COPY-PASTE IT.
|
||||
set_target_properties(core_tests PROPERTIES first-level-tests-dependency TRUE)
|
||||
add_dependencies(tests core_tests)
|
||||
|
||||
include(cmake/Testing.cmake)
|
||||
|
||||
# ----- Template Based Generator -----------------------------------------------
|
||||
include(cmake/TemplateBasedGen.cmake)
|
||||
|
||||
# ----- Enable panda assemblies building ---------------------------------------
|
||||
include(cmake/PandaAssembly.cmake)
|
||||
|
||||
# Some compilers use x87 fp instructions by default in 32-bit mode.
|
||||
# We need to use SSE one to correspond x86_64 build.
|
||||
if (PANDA_TARGET_X86)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -msse3")
|
||||
endif()
|
||||
|
||||
# ----- Targets ----------------------------------------------------------------
|
||||
|
||||
execute_process(COMMAND ${PANDA_ROOT}/scripts/install-third-party
|
||||
WORKING_DIRECTORY ${PANDA_ROOT}
|
||||
RESULT_VARIABLE THIRD_PARTY_OK)
|
||||
if (NOT THIRD_PARTY_OK EQUAL 0)
|
||||
message(FATAL_ERROR "Unable to install required third-party dependencies")
|
||||
endif()
|
||||
|
||||
if(PANDA_WITH_TOOLCHAIN)
|
||||
add_subdirectory(isa)
|
||||
|
||||
set(SECUREC_ROOT ${PANDA_THIRD_PARTY_SOURCES_DIR}/utils_native/base)
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_CONFIG_DIR}/securec)
|
||||
add_subdirectory(libpandabase)
|
||||
|
||||
set(ZLIB_ROOT ${PANDA_THIRD_PARTY_SOURCES_DIR}/zlib)
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_CONFIG_DIR}/zlib)
|
||||
add_subdirectory(libziparchive)
|
||||
|
||||
add_subdirectory(libpandafile)
|
||||
if(NOT PANDA_TARGET_WINDOWS)
|
||||
add_subdirectory(libpandafile/external)
|
||||
endif()
|
||||
|
||||
add_subdirectory(assembler)
|
||||
add_subdirectory(disassembler)
|
||||
add_subdirectory(static_linker)
|
||||
|
||||
if(PANDA_WITH_RUNTIME)
|
||||
add_subdirectory(verification)
|
||||
endif()
|
||||
|
||||
if(PANDA_WITH_COMPILER)
|
||||
add_subdirectory(bytecode_optimizer)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(PANDA_WITH_COMPILER)
|
||||
add_subdirectory(cross_values)
|
||||
if (PANDA_TARGET_X86 OR PANDA_TARGET_AMD64)
|
||||
set(ASMJIT_STATIC TRUE)
|
||||
set(PREV_CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-bitwise-instead-of-logical -Wno-unused-but-set-variable -Wno-deprecated-copy -Wno-unknown-warning-option")
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_SOURCES_DIR}/asmjit)
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_SOURCES_DIR}/zydis)
|
||||
set(CMAKE_CXX_FLAGS "${PREV_CMAKE_CXX_FLAGS}")
|
||||
endif()
|
||||
|
||||
if (PANDA_LLVMAOT)
|
||||
add_subdirectory(libllvmaot)
|
||||
endif()
|
||||
|
||||
set(PREV_CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-bitwise-instead-of-logical -Wno-unknown-warning-option")
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_SOURCES_DIR}/vixl)
|
||||
set(CMAKE_CXX_FLAGS "${PREV_CMAKE_CXX_FLAGS}")
|
||||
add_subdirectory(irtoc)
|
||||
add_subdirectory(compiler/optimizer/code_generator)
|
||||
add_subdirectory(compiler)
|
||||
set(IRTOC_INTRINSICS_YAML ${PANDA_ROOT}/irtoc/intrinsics.yaml)
|
||||
# Irtoc is built within the host tools in cross-compiling mode.
|
||||
if(NOT (CMAKE_CROSSCOMPILING OR PANDA_TARGET_OHOS))
|
||||
add_subdirectory(irtoc/backend)
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_SOURCES_DIR}/elfio)
|
||||
endif()
|
||||
else()
|
||||
panda_add_library(arkcompiler ${PANDA_DEFAULT_LIB_TYPE})
|
||||
panda_add_library(arkbytecodeopt ${PANDA_DEFAULT_LIB_TYPE})
|
||||
panda_add_library(arkaotmanager ${PANDA_DEFAULT_LIB_TYPE})
|
||||
endif()
|
||||
|
||||
if(PANDA_WITH_RUNTIME)
|
||||
add_subdirectory(pandastdlib)
|
||||
|
||||
if(NOT PANDA_TARGET_WINDOWS)
|
||||
add_subdirectory(dprof)
|
||||
endif()
|
||||
|
||||
add_subdirectory(runtime)
|
||||
|
||||
add_subdirectory(panda)
|
||||
|
||||
add_subdirectory(verification/verifier)
|
||||
|
||||
set(ICU_ROOT ${PANDA_THIRD_PARTY_SOURCES_DIR}/icu)
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_CONFIG_DIR}/icu)
|
||||
endif()
|
||||
|
||||
# ----- Testing ----------------------------------------------------------------
|
||||
|
||||
if(PANDA_WITH_TESTS)
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_SOURCES_DIR}/googletest)
|
||||
set_target_properties(gtest PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set_target_properties(gtest_main PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set_target_properties(gmock PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
option(RC_ENABLE_RTTI OFF)
|
||||
if(NOT PANDA_USE_PREBUILT_TARGETS)
|
||||
# Skip rapidcheck building when using prebuilt targets, because we don't need static
|
||||
# libraries at this stage
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_SOURCES_DIR}/rapidcheck)
|
||||
add_subdirectory(${PANDA_THIRD_PARTY_SOURCES_DIR}/rapidcheck/extras/gtest)
|
||||
panda_target_compile_options(rapidcheck PUBLIC "-fexceptions" "-fno-rtti" "-fPIC")
|
||||
endif()
|
||||
|
||||
add_subdirectory(tests)
|
||||
|
||||
add_custom_target(tests_full COMMENT "Running all test suites and code checks")
|
||||
add_dependencies(tests_full
|
||||
tests
|
||||
cmake-checker
|
||||
test-cmake-checker
|
||||
)
|
||||
|
||||
if (NOT PANDA_TARGET_MACOS)
|
||||
add_dependencies(tests_full code-style-check)
|
||||
endif()
|
||||
|
||||
add_subdirectory(scripts)
|
||||
|
||||
endif()
|
||||
|
||||
# ----- Aliases ----------------------------------------------------------------
|
||||
|
||||
add_custom_target(panda_bins COMMENT "Build all common Panda binaries")
|
||||
add_dependencies(panda_bins panda pandasm ark_disasm ark_link paoc verifier aspt_converter)
|
||||
|
||||
# ----- Benchmarking -----------------------------------------------------------
|
||||
|
||||
if(PANDA_WITH_BENCHMARKS)
|
||||
# NB! Please do not merge benchmarks and tests unless you want to mess with
|
||||
# slow builds, etc. If you want some coupling, you might want to make benchmarks
|
||||
# depend on tests some day.
|
||||
|
||||
add_custom_target(benchmarks COMMENT "Running all benchmark suites")
|
||||
add_subdirectory(tests/benchmarks)
|
||||
endif()
|
||||
|
||||
# ----- Plugins ----------------------------------------------------------------
|
||||
|
||||
add_subdirectory(plugins)
|
||||
include(cmake/PostPlugins.cmake)
|
||||
|
||||
# ----- Platforms --------------------------------------------------------------
|
||||
|
||||
add_subdirectory(platforms)
|
||||
|
||||
# ----- Extras ----------------------------------------------------------------
|
||||
|
||||
add_subdirectory(extras)
|
||||
|
||||
# ----- Quickening tool --------------------------------------------------------
|
||||
|
||||
add_subdirectory(quickener)
|
||||
|
||||
# ----- Panda tools -----------------------------------------------
|
||||
|
||||
add_subdirectory(tools)
|
||||
|
||||
# ----- Collecting core gtests paths for CI stash ---------------------------------
|
||||
# NB! This must be the last section!
|
||||
|
||||
# Check that the tests target has only first-level groups as dependencies.
|
||||
# If you want to create a new first-level group of tests, mark it as 'first-level-tests-dependency'
|
||||
# using the following command set_target_properties(<target> PROPERTIES first-level-tests-dependency TRUE)
|
||||
# and don't forget to handle it on CI.
|
||||
get_target_property(dependencies tests MANUALLY_ADDED_DEPENDENCIES)
|
||||
foreach(dep IN LISTS dependencies)
|
||||
get_target_property(first_level_dep ${dep} first-level-tests-dependency)
|
||||
if(NOT first_level_dep)
|
||||
message(FATAL_ERROR "Target ${dep} must not be added to tests dependencies directly.")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Write to a file the list of all binaries
|
||||
get_property(stash_files GLOBAL PROPERTY stash_list)
|
||||
list(JOIN stash_files "\n" file_content)
|
||||
file(WRITE ${PANDA_BINARY_ROOT}/core_stash_files.txt "${file_content}\n")
|
177
static_core/LICENSE
Normal file
177
static_core/LICENSE
Normal file
@ -0,0 +1,177 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
68
static_core/OAT.xml
Normal file
68
static_core/OAT.xml
Normal file
@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Copyright (c) 2022 Huawei Device Co., Ltd.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
This is the configuration file template for OpenHarmony OSS Audit Tool, please copy it to your project root dir and modify it refer to OpenHarmony/tools_oat/README.
|
||||
All configurations in this file will be merged to OAT-Default.xml, if you have any questions or concerns, please create issue in OpenHarmony/tools_oat and @jalenchen or chenyaxun.
|
||||
|
||||
licensefile:
|
||||
1.If the project don't have "LICENSE" in root dir, please define all the license files in this project in , OAT will check license files according to this rule.
|
||||
|
||||
policylist:
|
||||
1. policy: If the OAT-Default.xml policies do not meet your requirements, please add policies here.
|
||||
2. policyitem: The fields type, name, path, desc is required, and the fields rule, group, filefilter is optional,the default value is:
|
||||
<policyitem type="" name="" path="" desc="" rule="may" group="defaultGroup" filefilter="defaultPolicyFilter"/>
|
||||
3. policyitem type:
|
||||
"compatibility" is used to check license compatibility in the specified path;
|
||||
"license" is used to check source license header in the specified path;
|
||||
"copyright" is used to check source copyright header in the specified path;
|
||||
"import" is used to check source dependency in the specified path, such as import ... ,include ...
|
||||
"filetype" is used to check file type in the specified path, supported file types: archive, binary
|
||||
"filename" is used to check whether the specified file exists in the specified path(projectroot means the root dir of the project), supported file names: LICENSE, README, README.OpenSource
|
||||
4. policyitem name: This field is used for define the license, copyright, "*" means match all, the "!" prefix means could not match this value. For example, "!GPL" means can not use GPL license.
|
||||
5. policyitem path: This field is used for define the source file scope to apply this policyitem, the "!" prefix means exclude the files. For example, "!.*/lib/.*" means files in lib dir will be exclude while process this policyitem.
|
||||
6. policyitem rule and group: These two fields are used together to merge policy results. "may" policyitems in the same group means any one in this group passed, the result will be passed.
|
||||
7. policyitem filefilter: Used to bind filefilter which define filter rules.
|
||||
7. policyitem desc: Used to describe the reason of this policy item, committers will check this while merging the code.
|
||||
8. filefilter: Filter rules, the type filename is used to filter file name, the type filepath is used to filter file path.
|
||||
|
||||
Note:If the text contains special characters, please escape them according to the following rules:
|
||||
" == "
|
||||
& == &
|
||||
' == '
|
||||
< == <
|
||||
> == >
|
||||
-->
|
||||
|
||||
<configuration>
|
||||
<oatconfig>
|
||||
<licensefile></licensefile>
|
||||
<policylist>
|
||||
<policy name="projectPolicy" desc="">
|
||||
<policyitem type="compatibility" name="Apache" path=".*" desc="">
|
||||
</policy>
|
||||
</policylist>
|
||||
|
||||
<filefilterlist>
|
||||
<filefilter name="defaultFilter" desc="Files not to check">
|
||||
<filteritem type="filename" name="*.iml|*.json|*.txt|*.png" desc="desc files"/>
|
||||
<filteritem type="filepath" name=".*/docs/.*" desc="Docs files"/>
|
||||
<filteritem type="filepath" name=".*/docs/diagrams/.*" desc="Docs files"/>
|
||||
<filteritem type="filepath" name="scripts/dep-lists/.*" desc="Dependency lists"/>
|
||||
<filteritem type="filepath" name="third_party/.*" desc="Third party"/>
|
||||
<filteritem type="filepath" name="plugins/java/.*" desc="Plugin for java"/>
|
||||
</filefilter>
|
||||
</filefilterlist>
|
||||
</oatconfig>
|
||||
</configuration>
|
171
static_core/README.md
Normal file
171
static_core/README.md
Normal file
@ -0,0 +1,171 @@
|
||||
# Bootstrapping
|
||||
|
||||
Currently an officially supported host OS for development, building and testing is Ubuntu 18.04 and Ubuntu 20.04.
|
||||
The full list of packages required for building and testing the project is specified in
|
||||
`scripts/deps-lists` files. These packages can be installed either manually or by running
|
||||
a bootstrap script:
|
||||
|
||||
```
|
||||
$ sudo ./scripts/install-deps-ubuntu
|
||||
```
|
||||
|
||||
For more bootstrapping options, run:
|
||||
|
||||
```
|
||||
$ sudo ./scripts/install-deps-ubuntu --help
|
||||
```
|
||||
|
||||
E.g. for development purposes you should run:
|
||||
|
||||
```
|
||||
$ sudo ./scripts/install-deps-ubuntu -i=dev
|
||||
```
|
||||
|
||||
If you want additionally to install python dependencies for running tests add a parameter `-i=test`:
|
||||
|
||||
|
||||
```
|
||||
$ sudo ./scripts/install-deps-ubuntu -i=dev -i=test
|
||||
```
|
||||
It creates a virtual environment .venv-panda in your home directory with all required dependencies.
|
||||
Later, tests python scripts can activate this environment. If you already have run with the parameter `-i=test`
|
||||
the second time it might be skipped.
|
||||
|
||||
|
||||
# Third party
|
||||
|
||||
Panda uses third party libraries. To install the libraries and apply patches, run:
|
||||
|
||||
```
|
||||
$ ./scripts/install-third-party --force-clone
|
||||
```
|
||||
|
||||
# Building
|
||||
|
||||
Assuming your system is bootstrapped, please run the following commands in the root of the project:
|
||||
|
||||
```
|
||||
$ mkdir panda-build
|
||||
$ cd panda-build
|
||||
$ cmake /path/to/panda/repository -GNinja
|
||||
$ ninja
|
||||
```
|
||||
|
||||
This will build Panda in debug mode with your default C++ compiler. All supported compilers can be
|
||||
found in `cmake/toolchain`. E.g., to build with Clang 14, pass a path to the corresponding toolchain
|
||||
file during configuration:
|
||||
|
||||
```
|
||||
$ cmake -DCMAKE_TOOLCHAIN_FILE=/path/to/panda/repository/cmake/toolchain/host_clang_14.cmake /path/to/panda/repository
|
||||
```
|
||||
|
||||
## Explicitly setting build types
|
||||
|
||||
Recommended way to build Panda is to set `CMAKE_BUILD_TYPE` variable explicitly during configurations. Supported values are:
|
||||
|
||||
| Mode | Assertions | Optimizations | Debug info |
|
||||
| ---- | ---------- | ------------- | ---------- |
|
||||
| `Debug ` | Yes | None (CMake default) | `-g` (CMake default) |
|
||||
| `Release` | No | `-O3` (CMake default) | None (CMake default) |
|
||||
| `FastVerify` | Yes | `-O2` | `-ggdb3` |
|
||||
|
||||
Notes:
|
||||
|
||||
* Other common modes (`RelWithDebInfo`, `MinSizeRel`, `DebugDetailed`) should work but they are not tested in CI.
|
||||
* Unlike `RelWithDebInfo`, `FastVerify` preserves assertions (and provides more verbose debug information).
|
||||
Use this build type for running heavy test suites when you want both fast-running code and debuggability.
|
||||
* `DebugDetailed` gives more debug information than `Debug`, it can be usefull for debugging unit tests for example.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
$ cmake -DCMAKE_BUILD_TYPE=Release ...
|
||||
```
|
||||
|
||||
## Running tests with QEMU for cross-compiled aarch64/arm builds
|
||||
|
||||
Recommended QEMU version for running testst is 6.2.0 (but 5.1+ should be ok, too). By default, it is downloaded and installed during environment bootstrap. Any system-installed package is left intact. If recommened QEMU version is not accessible via $PATH it can be specified during configuration time:
|
||||
|
||||
```
|
||||
# If QEMU is available as /opt/qemu-6.2.0/bin/qemu-aarch64
|
||||
$ cmake -DQEMU_PREFIX=/opt/qemu-6.2.0 ...
|
||||
```
|
||||
|
||||
## Building with GN
|
||||
|
||||
1. Getting GN binary
|
||||
|
||||
```
|
||||
$ git clone https://gn.googlesource.com/gn
|
||||
$ cd gn
|
||||
$ python build/gen.py
|
||||
$ ninja -C out
|
||||
```
|
||||
|
||||
2. Build panda using gn (`ark_asm`, `ark_disasm`, `ark_aot`, `ark_aotdump`, `c2abc`, `ark_bin`, `es2panda`, `verifier_bin` and `ark` targets are supported)
|
||||
|
||||
```
|
||||
$ cd /path/to/panda/repository
|
||||
$ /path/to/gn/repository/out/gn gen out
|
||||
$ ninja -C out ark
|
||||
```
|
||||
When standard system, use
|
||||
```
|
||||
$ cd /path/to/panda/repository
|
||||
$ /path/to/gn/repository/out/gn --args=-is_standard_system=true gen out
|
||||
$ ninja -C out <target name>
|
||||
```
|
||||
|
||||
|
||||
## Further reading
|
||||
|
||||
* For more details, please see [build system readme](cmake/README.md).
|
||||
|
||||
# Testing
|
||||
|
||||
For testing, the following umbrella targets that guarantee building prior to running may be used:
|
||||
|
||||
* `tests`, for running all testing suites.
|
||||
* `tests_full`, for running all testing suites and various code linters.
|
||||
|
||||
# Clang tools
|
||||
|
||||
`clang-format` and `clang-tidy` checks are integrated into build system and can be called by target of build system:
|
||||
```
|
||||
$ ninja code-style-check # clang-format
|
||||
$ ninja clang-tidy-check # clang-tidy
|
||||
```
|
||||
|
||||
# Test coverage
|
||||
|
||||
In order to measure bytecode optimizer coverage, configure your build with -DENABLE_BYTECODE_OPTIMIZER_COVERAGE=true. Then run:
|
||||
```
|
||||
$ ninja bytecode_optimizer_coverage
|
||||
```
|
||||
|
||||
# Benchmarking
|
||||
|
||||
To build and run benchmarks, please use the umbrella target `benchmarks` or any of its
|
||||
dependencies. Please see the root `CMakeLists.txt` for more details.
|
||||
|
||||
NB! Make sure that you configure your build with `-DCMAKE_BUILD_TYPE=Release`, otherwise
|
||||
your run will most likely be dead slow.
|
||||
|
||||
# Running
|
||||
|
||||
## Running assembler
|
||||
|
||||
Assuming that you are in `panda-build` directory, please run:
|
||||
|
||||
```
|
||||
$ ./bin/ark_asm /path/to/panda-assembly.pa /path/to/binary/output.abc
|
||||
```
|
||||
|
||||
## Running interpreter
|
||||
|
||||
Assuming that your main function is defined as `.function main(...)` in the assembly listing,
|
||||
and `/path/to/binary/output.abc` is the result of the assembler, please run:
|
||||
|
||||
```
|
||||
$ ./bin/ark /path/to/binary/output.abc _GLOBAL::main
|
||||
```
|
335
static_core/ark_config.gni
Normal file
335
static_core/ark_config.gni
Normal file
@ -0,0 +1,335 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//arkcompiler/runtime_core/static_core/ark_root.gni")
|
||||
import("//build/ohos.gni")
|
||||
|
||||
ark_subsystem_name = "arkcompiler"
|
||||
ark_part_name = "runtime_core"
|
||||
|
||||
if (is_standard_system) {
|
||||
import("$ark_root/platforms/ohos/ark_config.gni")
|
||||
} else {
|
||||
import("$ark_root/platforms/mobile/ark_config.gni")
|
||||
}
|
||||
|
||||
declare_args() {
|
||||
ark_enabled_plugins = default_ark_enabled_plugins
|
||||
extras = []
|
||||
if (!defined(is_ohos)) {
|
||||
is_ohos = false
|
||||
}
|
||||
if (!defined(is_standard_system)) {
|
||||
is_standard_system = true
|
||||
}
|
||||
}
|
||||
|
||||
if (current_cpu == "arm") {
|
||||
if (!defined(arm_float_abi) || arm_float_abi == "") {
|
||||
arm_float_abi = "softfp"
|
||||
}
|
||||
|
||||
assert(arm_float_abi == "soft" || arm_float_abi == "softfp" ||
|
||||
arm_float_abi == "hard",
|
||||
"arm_float_abi should be soft, softfp or hard")
|
||||
}
|
||||
|
||||
ark_root_gen_dir = "$root_gen_dir/ark_sig"
|
||||
|
||||
concat_gen_dir =
|
||||
get_label_info("$ark_root:concat_plugins_yamls", "target_gen_dir")
|
||||
ark_plugin_options_yaml = "$concat_gen_dir/plugin_options.yaml"
|
||||
|
||||
isa_gen_dir = get_label_info("$ark_root/isa:isa_combine", "target_gen_dir")
|
||||
ark_isa_yaml = "$isa_gen_dir/isa.yaml"
|
||||
is_llvmaot = false
|
||||
ark_enable_global_register_variables = true
|
||||
enable_bytecode_optimizer = true
|
||||
enable_relayout_profile = false
|
||||
|
||||
sdk_libc_secshared_dep = ""
|
||||
sdk_libc_secshared_config = ""
|
||||
|
||||
if (ark_standalone_build) {
|
||||
sdk_libc_secshared_dep = "$ark_third_party_root/securec:libc_secshared"
|
||||
sdk_libc_secshared_config =
|
||||
"$ark_third_party_root/securec:libsec_public_config"
|
||||
|
||||
if (is_mingw || is_mac || is_linux) {
|
||||
sdk_libc_secshared_dep = "$ark_third_party_root/securec:libc_secstatic"
|
||||
}
|
||||
} else {
|
||||
# For OpenHarmony build, always link with the static lib:
|
||||
sdk_libc_secshared_dep =
|
||||
"$ark_third_party_root/bounds_checking_function:libsec_static"
|
||||
sdk_libc_secshared_config =
|
||||
"$ark_third_party_root/bounds_checking_function:libsec_public_config"
|
||||
}
|
||||
|
||||
is_mob = !is_ohos && !is_linux && !is_mingw && !is_mac &&
|
||||
(current_cpu != "arm" || is_wearable_product)
|
||||
|
||||
## TODO add other arch
|
||||
|
||||
# Generate file for a template and YAML data provided.
|
||||
#
|
||||
# Mandatory arguments:
|
||||
# data_file -- YAML data full name
|
||||
# template_file -- template full name
|
||||
# output_file -- output file full name
|
||||
# requires -- a list of scripts that provide data-querying API for templates
|
||||
# extra_dependencies -- a list of files that should be considered as dependencies, must be lable
|
||||
template("ark_gen_file") {
|
||||
assert(defined(invoker.data_file), "data_file is required!")
|
||||
assert(defined(invoker.template_file), "template_file is required!")
|
||||
assert(defined(invoker.output_file), "output_file is required!")
|
||||
|
||||
requires = ""
|
||||
if (defined(invoker.requires)) {
|
||||
requires = string_join(",", rebase_path(invoker.requires, root_build_dir))
|
||||
}
|
||||
|
||||
extra_dependencies = []
|
||||
if (defined(invoker.extra_dependencies)) {
|
||||
extra_dependencies += invoker.extra_dependencies
|
||||
}
|
||||
|
||||
positional_argv = []
|
||||
if (defined(invoker.extra_argv)) {
|
||||
positional_argv += invoker.extra_argv
|
||||
}
|
||||
keyword_argv = [
|
||||
"--template",
|
||||
rebase_path(invoker.template_file, root_build_dir),
|
||||
"--data",
|
||||
rebase_path(invoker.data_file, root_build_dir),
|
||||
"--require",
|
||||
requires,
|
||||
"--output",
|
||||
rebase_path(invoker.output_file),
|
||||
]
|
||||
|
||||
action("$target_name") {
|
||||
script = "$ark_root/isa/gen.rb"
|
||||
|
||||
# rerun action when data file or template file update
|
||||
inputs = [
|
||||
invoker.template_file,
|
||||
invoker.data_file,
|
||||
]
|
||||
outputs = [ invoker.output_file ]
|
||||
args = positional_argv + keyword_argv
|
||||
deps = extra_dependencies
|
||||
}
|
||||
}
|
||||
|
||||
template("concat_yamls") {
|
||||
assert(defined(invoker.output_file), "output_file is required!")
|
||||
assert(defined(invoker.default_file), "default_file is required!")
|
||||
|
||||
extra_dependencies = []
|
||||
if (defined(invoker.extra_dependencies)) {
|
||||
extra_dependencies += invoker.extra_dependencies
|
||||
}
|
||||
|
||||
outputs = [ invoker.output_file ]
|
||||
|
||||
action("$target_name") {
|
||||
script = "$ark_root/templates/concat_yamls.sh"
|
||||
|
||||
# rerun action when data file or template file update
|
||||
inputs = [ invoker.default_file ]
|
||||
|
||||
args = [
|
||||
rebase_path(invoker.output_file, root_build_dir),
|
||||
rebase_path(invoker.default_file, root_build_dir),
|
||||
]
|
||||
|
||||
foreach(yaml, invoker.add_yamls) {
|
||||
args += [ rebase_path(yaml, root_build_dir) ]
|
||||
}
|
||||
|
||||
deps = extra_dependencies
|
||||
}
|
||||
}
|
||||
|
||||
template("merge_yamls") {
|
||||
assert(defined(invoker.output_file), "output_file is required!")
|
||||
assert(defined(invoker.add_yamls), "add_yamls is required!")
|
||||
|
||||
extra_dependencies = []
|
||||
if (defined(invoker.extra_dependencies)) {
|
||||
extra_dependencies += invoker.extra_dependencies
|
||||
}
|
||||
|
||||
outputs = [ invoker.output_file ]
|
||||
|
||||
action("$target_name") {
|
||||
script = "$ark_root/templates/merge.rb"
|
||||
|
||||
data = []
|
||||
foreach(yaml, invoker.add_yamls) {
|
||||
data += [ rebase_path(yaml, root_build_dir) ]
|
||||
}
|
||||
args = [
|
||||
"-d",
|
||||
string_join(",", data),
|
||||
"-o",
|
||||
rebase_path(invoker.output_file, root_build_dir),
|
||||
]
|
||||
|
||||
deps = extra_dependencies
|
||||
}
|
||||
}
|
||||
|
||||
# Generate files based on templates and YAML data provided.
|
||||
# Adds targets for every template. Also adds a target for the whole function invocation
|
||||
# with name ${data_name}_gen_${PROJECT_NAME} for ease of declaring dependencies on generated files.
|
||||
#
|
||||
# Mandatory arguments:
|
||||
# * data -- data source, YAML file
|
||||
# * template_files -- a list of templates to generate files
|
||||
# * requires -- a list of Ruby scripts that provide data-querying API for templates
|
||||
#
|
||||
# Optional arguments:
|
||||
# * sources -- a directory with templates, default is ${PROJECT_SOURCE_DIR}/templates
|
||||
# * destination -- a directory for output files, default is ${PANDA_BINARY_ROOT}
|
||||
# * extra_dependencies -- a list of files that should be considered as dependencies
|
||||
# * extra_argv -- a list of positional arguments that could be accessed in '.erb' files via ARGV[]
|
||||
template("ark_gen") {
|
||||
assert(defined(invoker.data), "data were not passed to ark_gen")
|
||||
assert(defined(invoker.template_files),
|
||||
"template_files were not passed to ark_gen")
|
||||
|
||||
dir = ""
|
||||
if (defined(invoker.sources)) {
|
||||
dir = invoker.sources
|
||||
} else {
|
||||
dir = "templates"
|
||||
}
|
||||
|
||||
destination = ""
|
||||
if (defined(invoker.destination)) {
|
||||
destination = invoker.destination
|
||||
} else {
|
||||
destination = target_out_dir
|
||||
}
|
||||
|
||||
input_requires = ""
|
||||
if (defined(invoker.requires)) {
|
||||
input_requires = invoker.requires
|
||||
}
|
||||
|
||||
foreach(t, invoker.template_files) {
|
||||
name = string_replace(t, ".erb", "")
|
||||
output = "${destination}/${name}"
|
||||
name = string_replace(name, ".", "_")
|
||||
name = string_replace(name, "/", "_")
|
||||
target = "${target_name}_${name}"
|
||||
|
||||
ark_gen_file(target) {
|
||||
data_file = invoker.data
|
||||
template_file = "${dir}/${t}"
|
||||
output_file = output
|
||||
requires = input_requires
|
||||
extra_dependencies = []
|
||||
if (defined(invoker.extra_dependencies)) {
|
||||
extra_dependencies += invoker.extra_dependencies
|
||||
}
|
||||
extra_argv = []
|
||||
if (defined(invoker.extra_argv)) {
|
||||
extra_argv += invoker.extra_argv
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Calls `ark_gen` for ISA YAML.
|
||||
# Adds targets for every template. Also adds a target for the whole function invocation
|
||||
# with name isa_gen_${PROJECT_NAME} for ease of declaring dependencies on generated files.
|
||||
#
|
||||
# Mandatory arguments:
|
||||
# * template_files -- a list of templates to generate files
|
||||
#
|
||||
# Optional arguments:
|
||||
# * sources -- a directory with templates, default is ${PROJECT_SOURCE_DIR}/templates
|
||||
# * destination -- a directory for output files, default is ${target_out_dir}
|
||||
# * requires -- if defined, will require additional Ruby files for template generation, must be list
|
||||
# * extra_dependencies -- a list of files that should be considered as dependencies lable, must be list, not used
|
||||
template("ark_isa_gen") {
|
||||
isa_data = "$ark_isa_yaml"
|
||||
isa_requires = [ "$ark_root/isa/isapi.rb" ]
|
||||
if (defined(invoker.requires)) {
|
||||
isa_requires += invoker.requires
|
||||
}
|
||||
|
||||
dependencies = [ "$ark_root/isa:isa_combine" ]
|
||||
if (defined(invoker.extra_dependencies)) {
|
||||
dependencies += invoker.extra_dependencies
|
||||
}
|
||||
|
||||
ark_gen("$target_name") {
|
||||
data = isa_data
|
||||
template_files = invoker.template_files
|
||||
sources = invoker.sources
|
||||
destination = invoker.destination
|
||||
requires = isa_requires
|
||||
extra_dependencies = dependencies
|
||||
}
|
||||
}
|
||||
|
||||
# Run ark_asm
|
||||
#
|
||||
# Arguments:
|
||||
# * input_file -- Path to the source assembly code
|
||||
# * output_file -- Path to the generated binary code
|
||||
template("ark_asm_gen") {
|
||||
action(target_name) {
|
||||
ark_asm_root_out =
|
||||
get_label_info("$ark_root/assembler:arkts_asm(${host_toolchain})",
|
||||
"root_out_dir")
|
||||
script =
|
||||
ark_asm_root_out + "/$ark_subsystem_name/$ark_part_name/ark_asm"
|
||||
|
||||
inputs = [ invoker.input_file ]
|
||||
outputs = [ invoker.output_file ]
|
||||
args = [
|
||||
rebase_path(invoker.input_file, root_build_dir),
|
||||
rebase_path(invoker.output_file, root_build_dir),
|
||||
]
|
||||
|
||||
deps = [ "$ark_root/assembler:arkts_asm(${host_toolchain})" ]
|
||||
}
|
||||
}
|
||||
|
||||
# Run es2panda
|
||||
#
|
||||
# Arguments:
|
||||
# The same you would pass to action except script and deps.
|
||||
template("es2panda_gen") {
|
||||
action(target_name) {
|
||||
es2panda_root_out = get_label_info(
|
||||
"$ark_root/plugins/ecmascript/es2panda/aot:es2panda(${host_toolchain})",
|
||||
"root_out_dir")
|
||||
script =
|
||||
es2panda_root_out + "/$ark_subsystem_name/$ark_part_name/es2panda"
|
||||
deps = [
|
||||
"$ark_root/plugins/ecmascript/es2panda/aot:es2panda(${host_toolchain})",
|
||||
]
|
||||
|
||||
inputs = invoker.inputs
|
||||
outputs = invoker.outputs
|
||||
sources = invoker.sources
|
||||
args = invoker.args
|
||||
}
|
||||
}
|
24
static_core/ark_root.gni
Normal file
24
static_core/ark_root.gni
Normal file
@ -0,0 +1,24 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
if (!defined(ark_standalone_build)) {
|
||||
ark_standalone_build = false
|
||||
}
|
||||
|
||||
if (ark_standalone_build) {
|
||||
ark_root = "//"
|
||||
} else {
|
||||
ark_root = "//arkcompiler/runtime_core/static_core"
|
||||
}
|
||||
|
||||
ark_third_party_root = "//third_party"
|
185
static_core/assembler/BUILD.gn
Normal file
185
static_core/assembler/BUILD.gn
Normal file
@ -0,0 +1,185 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//arkcompiler/runtime_core/static_core/ark_config.gni")
|
||||
import("//build/ohos.gni")
|
||||
import("$ark_root/plugins/plugins.gni")
|
||||
|
||||
config("arkassembler_public_config") {
|
||||
include_dirs = [
|
||||
"$ark_root/assembler",
|
||||
"$target_gen_dir",
|
||||
"$target_gen_dir/include",
|
||||
"$ark_root_gen_dir",
|
||||
"$ark_root",
|
||||
]
|
||||
|
||||
configs = [ "$ark_root/runtime:profiling_gen_public_config" ]
|
||||
|
||||
defines = [ "PANDA_WITH_ECMASCRIPT" ]
|
||||
}
|
||||
|
||||
libarkassembler_sources = [
|
||||
"$target_gen_dir/ins_to_string.cpp",
|
||||
"annotation.cpp",
|
||||
"assembly-emitter.cpp",
|
||||
"assembly-ins.cpp",
|
||||
"assembly-parser.cpp",
|
||||
"assembly-program.cpp",
|
||||
"assembly-type.cpp",
|
||||
"context.cpp",
|
||||
"extensions/extensions.cpp",
|
||||
"lexer.cpp",
|
||||
"meta.cpp",
|
||||
]
|
||||
libarkassembler_sources += plugin_libarkassembler_sources
|
||||
|
||||
libarkassembler_configs = [
|
||||
sdk_libc_secshared_config,
|
||||
"$ark_root:ark_config",
|
||||
":arkassembler_public_config",
|
||||
"$ark_root/runtime:arkruntime_public_config",
|
||||
"$ark_root/libpandabase:arkbase_public_config",
|
||||
"$ark_root/libpandafile:arkfile_public_config",
|
||||
"$ark_root/compiler:arkcompiler_public_config",
|
||||
]
|
||||
libarkassembler_configs += plugin_libarkassembler_configs
|
||||
|
||||
source_set("libarkassembler_static") {
|
||||
sources = libarkassembler_sources
|
||||
|
||||
public_configs = libarkassembler_configs
|
||||
|
||||
deps = [
|
||||
":ark_asm_meta_gen_h",
|
||||
":ark_asm_register_extensions_h",
|
||||
":isa_gen_libarkassembler_ins_create_api_h",
|
||||
":isa_gen_libarkassembler_ins_emit_h",
|
||||
":isa_gen_libarkassembler_ins_to_string_cpp",
|
||||
":isa_gen_libarkassembler_isa_h",
|
||||
":isa_gen_libarkassembler_opcode_parsing_h",
|
||||
":isa_gen_libarkassembler_operand_types_print_h",
|
||||
"$ark_root/compiler:libarktscompiler",
|
||||
"$ark_root/libpandabase:libarktsbase",
|
||||
"$ark_root/libpandafile:libarktsfile",
|
||||
"$ark_root/runtime:profiling_gen_profiling_gen_h",
|
||||
sdk_libc_secshared_dep,
|
||||
]
|
||||
|
||||
deps += plugin_assembler_deps
|
||||
}
|
||||
|
||||
ohos_shared_library("libarktsassembler") {
|
||||
deps = [ ":libarkassembler_static" ]
|
||||
|
||||
output_extension = "so"
|
||||
if (is_mingw) {
|
||||
output_extension = "dll"
|
||||
}
|
||||
part_name = ark_part_name
|
||||
subsystem_name = "$ark_subsystem_name"
|
||||
}
|
||||
|
||||
source_set("libarkassembler_frontend_set_static") {
|
||||
sources = libarkassembler_sources
|
||||
|
||||
public_configs = libarkassembler_configs
|
||||
|
||||
deps = [
|
||||
":ark_asm_meta_gen_h",
|
||||
":ark_asm_register_extensions_h",
|
||||
":isa_gen_libarkassembler_ins_create_api_h",
|
||||
":isa_gen_libarkassembler_ins_emit_h",
|
||||
":isa_gen_libarkassembler_ins_to_string_cpp",
|
||||
":isa_gen_libarkassembler_isa_h",
|
||||
":isa_gen_libarkassembler_opcode_parsing_h",
|
||||
":isa_gen_libarkassembler_operand_types_print_h",
|
||||
"$ark_root/libpandafile:libarktsfile_frontend_static",
|
||||
"$ark_root/runtime:profiling_gen_profiling_gen_h",
|
||||
sdk_libc_secshared_dep,
|
||||
]
|
||||
|
||||
deps += plugin_assembler_deps
|
||||
}
|
||||
|
||||
ohos_static_library("libarktsassembler_frontend_static") {
|
||||
deps = [ ":libarkassembler_frontend_set_static" ]
|
||||
part_name = ark_part_name
|
||||
subsystem_name = "$ark_subsystem_name"
|
||||
}
|
||||
|
||||
source_set("ark_asm_static") {
|
||||
sources = [ "pandasm.cpp" ]
|
||||
|
||||
include_dirs = [
|
||||
"$target_gen_dir",
|
||||
]
|
||||
|
||||
public_configs = [
|
||||
sdk_libc_secshared_config,
|
||||
":arkassembler_public_config",
|
||||
"$ark_root:ark_config",
|
||||
"$ark_root/libpandabase:arkbase_public_config",
|
||||
"$ark_root/libpandafile:arkfile_public_config",
|
||||
"$ark_root/compiler:arkcompiler_public_config",
|
||||
"$ark_root/runtime:arkruntime_public_config",
|
||||
]
|
||||
|
||||
deps = [
|
||||
":libarktsassembler_frontend_static",
|
||||
"$ark_root/bytecode_optimizer:libarktsbytecodeopt_frontend_static",
|
||||
"$ark_root/libpandabase:libarktsbase_frontend_static",
|
||||
"$ark_root/libpandafile:libarktsfile_frontend_static",
|
||||
]
|
||||
}
|
||||
|
||||
ohos_executable("arkts_asm") {
|
||||
deps = [ ":ark_asm_static" ]
|
||||
|
||||
libs = platform_libs
|
||||
ldflags = platform_ldflags
|
||||
|
||||
install_enable = true
|
||||
part_name = ark_part_name
|
||||
subsystem_name = "$ark_subsystem_name"
|
||||
}
|
||||
|
||||
ark_isa_gen("isa_gen_libarkassembler") {
|
||||
template_files = [
|
||||
"isa.h.erb",
|
||||
"ins_emit.h.erb",
|
||||
"ins_to_string.cpp.erb",
|
||||
"ins_create_api.h.erb",
|
||||
"opcode_parsing.h.erb",
|
||||
"operand_types_print.h.erb",
|
||||
]
|
||||
sources = "templates"
|
||||
destination = "$target_gen_dir"
|
||||
requires = [
|
||||
"asm_isapi.rb",
|
||||
"../libpandafile/pandafile_isapi.rb",
|
||||
]
|
||||
}
|
||||
|
||||
ark_gen_file("ark_asm_meta_gen_h") {
|
||||
template_file = "templates/meta_gen.cpp.erb"
|
||||
data_file = "metadata.yaml"
|
||||
requires = [ "asm_metadata.rb" ]
|
||||
output_file = "$target_gen_dir/meta_gen.h"
|
||||
}
|
||||
|
||||
ark_gen_file("ark_asm_register_extensions_h") {
|
||||
extra_dependencies = [ "$ark_root:concat_plugins_yamls" ]
|
||||
template_file = "extensions/register_extensions.h.erb"
|
||||
data_file = "$ark_plugin_options_yaml"
|
||||
requires = [ "$ark_root/templates/plugin_options.rb" ]
|
||||
output_file = "$target_gen_dir/register_extensions.h"
|
||||
}
|
136
static_core/assembler/CMakeLists.txt
Normal file
136
static_core/assembler/CMakeLists.txt
Normal file
@ -0,0 +1,136 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.3.2 FATAL_ERROR)
|
||||
project(assembler CXX)
|
||||
|
||||
panda_add_executable(ark_asm pandasm.cpp)
|
||||
|
||||
set(PANDASM_BIN_TESTS ${CMAKE_CURRENT_BINARY_DIR}/tests)
|
||||
file(MAKE_DIRECTORY "${PANDASM_BIN_TESTS}")
|
||||
|
||||
panda_isa_gen(
|
||||
TEMPLATES
|
||||
"isa.h.erb"
|
||||
"ins_emit.h.erb"
|
||||
"ins_to_string.cpp.erb"
|
||||
"ins_create_api.h.erb"
|
||||
"opcode_parsing.h.erb"
|
||||
"operand_types_print.h.erb"
|
||||
REQUIRES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/asm_isapi.rb"
|
||||
"${PANDA_ROOT}/libpandafile/pandafile_isapi.rb"
|
||||
)
|
||||
|
||||
set(SOURCES
|
||||
lexer.cpp
|
||||
annotation.cpp
|
||||
assembly-emitter.cpp
|
||||
assembly-parser.cpp
|
||||
assembly-program.cpp
|
||||
assembly-type.cpp
|
||||
assembly-ins.cpp
|
||||
context.cpp
|
||||
meta.cpp
|
||||
ins_to_string.cpp
|
||||
extensions/extensions.cpp
|
||||
)
|
||||
|
||||
set(META_GEN_H ${CMAKE_CURRENT_BINARY_DIR}/meta_gen.h)
|
||||
panda_gen_file(
|
||||
DATAFILE ${CMAKE_CURRENT_SOURCE_DIR}/metadata.yaml
|
||||
TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/templates/meta_gen.cpp.erb
|
||||
OUTPUTFILE ${META_GEN_H}
|
||||
REQUIRES ${CMAKE_CURRENT_SOURCE_DIR}/asm_metadata.rb
|
||||
)
|
||||
add_custom_target(meta_gen_h DEPENDS ${META_GEN_H})
|
||||
add_dependencies(panda_gen_files meta_gen_h)
|
||||
|
||||
panda_add_library(arkassembler_obj OBJECT ${SOURCES})
|
||||
add_dependencies(arkassembler_obj
|
||||
isa_gen_assembler
|
||||
arkfile
|
||||
meta_gen_h
|
||||
profiling_gen
|
||||
)
|
||||
|
||||
set_target_properties(arkassembler_obj PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
CXX_VISIBILITY_PRESET hidden
|
||||
VISIBILITY_INLINES_HIDDEN ON
|
||||
)
|
||||
|
||||
panda_target_include_directories(arkassembler_obj PUBLIC
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_BINARY_DIR}/libpandabase
|
||||
${PANDA_ROOT}
|
||||
${CMAKE_BINARY_DIR}
|
||||
)
|
||||
|
||||
panda_target_link_libraries(arkassembler_obj arkfile)
|
||||
panda_target_link_libraries(ark_asm arkassembler arkbase)
|
||||
if(PANDA_WITH_BYTECODE_OPTIMIZER)
|
||||
panda_target_link_libraries(ark_asm arkbytecodeopt)
|
||||
endif()
|
||||
|
||||
include_directories(${PANDA_ROOT}/libpandabase/)
|
||||
include_directories(${CMAKE_BINARY_DIR}/libpandafile/include/)
|
||||
|
||||
panda_add_library(arkassembler_static STATIC $<TARGET_OBJECTS:arkassembler_obj>)
|
||||
panda_target_link_libraries(arkassembler_static arkassembler_obj)
|
||||
|
||||
panda_add_gtest(
|
||||
NAME assembler_tests
|
||||
SOURCES
|
||||
tests/lexer_test.cpp
|
||||
tests/parser_test.cpp
|
||||
tests/emitter_test.cpp
|
||||
tests/mangling_tests.cpp
|
||||
LIBRARIES
|
||||
arkbase arkassembler_static
|
||||
SANITIZERS
|
||||
${PANDA_SANITIZERS_LIST}
|
||||
)
|
||||
if(TARGET assembler_tests)
|
||||
panda_target_compile_options(assembler_tests PUBLIC "-Wno-ignored-attributes")
|
||||
endif()
|
||||
|
||||
panda_add_sanitizers(TARGET arkassembler_obj SANITIZERS ${PANDA_SANITIZERS_LIST})
|
||||
panda_add_sanitizers(TARGET ark_asm SANITIZERS ${PANDA_SANITIZERS_LIST})
|
||||
|
||||
# TODO: remove after all components will use ark_asm instead of pandasm
|
||||
add_custom_target(pandasm ALL
|
||||
COMMAND cd $<TARGET_FILE_DIR:ark_asm> && ${CMAKE_COMMAND} -E create_symlink $<TARGET_FILE_NAME:ark_asm> pandasm)
|
||||
|
||||
add_dependencies(pandasm ark_asm)
|
||||
|
||||
if (TARGET host_tools_depends)
|
||||
add_dependencies(host_tools_depends arkassembler_obj)
|
||||
endif()
|
||||
|
||||
if (DEFINED PANDA_ROOT_BINARY_DIR)
|
||||
# Special case for host tool build.
|
||||
panda_target_include_directories(arkassembler_obj PUBLIC ${PANDA_ROOT_BINARY_DIR}/assembler)
|
||||
endif()
|
||||
|
||||
panda_add_library(arkassembler ${PANDA_DEFAULT_LIB_TYPE} $<TARGET_OBJECTS:arkassembler_obj>)
|
||||
panda_target_link_libraries(arkassembler arkassembler_obj)
|
||||
|
||||
if (PANDA_ENABLE_AFL)
|
||||
include("${PANDA_ROOT}/extras/fuzzing/Fuzzing.cmake")
|
||||
panda_substitute_libs(TARGET arkassembler_obj LIBS arkbase c_secshared arkfile)
|
||||
|
||||
panda_add_library(arkassembler_fuzz ${PANDA_DEFAULT_LIB_TYPE} $<TARGET_OBJECTS:arkassembler_obj_fuzz>)
|
||||
panda_target_link_libraries(arkassembler_fuzz arkassembler_obj_fuzz)
|
||||
endif()
|
245
static_core/assembler/annotation.cpp
Normal file
245
static_core/assembler/annotation.cpp
Normal file
@ -0,0 +1,245 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "annotation.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
std::unique_ptr<ScalarValue> InitScalarValue(const ScalarValue &sc_val)
|
||||
{
|
||||
std::unique_ptr<ScalarValue> copy_val;
|
||||
switch (sc_val.GetType()) {
|
||||
case Value::Type::U1: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::U1>(sc_val.GetValue<uint8_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::U8: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::U8>(sc_val.GetValue<uint8_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::U16: {
|
||||
copy_val =
|
||||
std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::U16>(sc_val.GetValue<uint16_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::U32: {
|
||||
copy_val =
|
||||
std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::U32>(sc_val.GetValue<uint32_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::U64: {
|
||||
copy_val =
|
||||
std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::U64>(sc_val.GetValue<uint64_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::I8: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::I8>(sc_val.GetValue<int8_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::I16: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::I16>(sc_val.GetValue<int16_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::I32: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::I32>(sc_val.GetValue<int32_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::I64: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::I64>(sc_val.GetValue<int64_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::F32: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::F32>(sc_val.GetValue<float>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::F64: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::F64>(sc_val.GetValue<double>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::STRING: {
|
||||
copy_val =
|
||||
std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::STRING>(sc_val.GetValue<std::string>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::STRING_NULLPTR: {
|
||||
copy_val = std::make_unique<ScalarValue>(
|
||||
ScalarValue::Create<Value::Type::STRING_NULLPTR>(sc_val.GetValue<int32_t>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::RECORD: {
|
||||
copy_val = std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::RECORD>(sc_val.GetValue<Type>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::METHOD: {
|
||||
copy_val =
|
||||
std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::METHOD>(sc_val.GetValue<std::string>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::ENUM: {
|
||||
copy_val =
|
||||
std::make_unique<ScalarValue>(ScalarValue::Create<Value::Type::ENUM>(sc_val.GetValue<std::string>()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::ANNOTATION: {
|
||||
copy_val = std::make_unique<ScalarValue>(
|
||||
ScalarValue::Create<Value::Type::ANNOTATION>(sc_val.GetValue<AnnotationData>()));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
copy_val = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return copy_val;
|
||||
}
|
||||
|
||||
std::unique_ptr<Value> MakingValue(const AnnotationElement &ann_elem)
|
||||
{
|
||||
std::unique_ptr<Value> copy_val;
|
||||
switch (ann_elem.GetValue()->GetType()) {
|
||||
case Value::Type::U1:
|
||||
case Value::Type::U8:
|
||||
case Value::Type::U16:
|
||||
case Value::Type::U32:
|
||||
case Value::Type::U64:
|
||||
case Value::Type::I8:
|
||||
case Value::Type::I16:
|
||||
case Value::Type::I32:
|
||||
case Value::Type::I64:
|
||||
case Value::Type::F32:
|
||||
case Value::Type::F64:
|
||||
case Value::Type::STRING:
|
||||
case Value::Type::STRING_NULLPTR:
|
||||
case Value::Type::RECORD:
|
||||
case Value::Type::METHOD:
|
||||
case Value::Type::ENUM:
|
||||
case Value::Type::ANNOTATION: {
|
||||
copy_val = InitScalarValue(*static_cast<ScalarValue *>(ann_elem.GetValue()));
|
||||
break;
|
||||
}
|
||||
case Value::Type::ARRAY: {
|
||||
Value::Type c_type;
|
||||
auto *elem_arr = static_cast<ArrayValue *>(ann_elem.GetValue());
|
||||
if (elem_arr->GetValues().empty()) {
|
||||
c_type = Value::Type::VOID;
|
||||
} else {
|
||||
c_type = elem_arr->GetValues().front().GetType();
|
||||
}
|
||||
std::vector<ScalarValue> sc_vals;
|
||||
for (const auto &sc_val : elem_arr->GetValues()) {
|
||||
sc_vals.push_back(*InitScalarValue(sc_val));
|
||||
}
|
||||
copy_val = std::make_unique<ArrayValue>(c_type, std::move(sc_vals));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
copy_val = nullptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return copy_val;
|
||||
}
|
||||
|
||||
AnnotationElement::AnnotationElement(const AnnotationElement &ann_elem)
|
||||
{
|
||||
this->value_ = MakingValue(ann_elem);
|
||||
this->name_ = ann_elem.GetName();
|
||||
}
|
||||
|
||||
AnnotationElement &AnnotationElement::operator=(const AnnotationElement &ann_elem)
|
||||
{
|
||||
if (this == &ann_elem) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
this->value_ = MakingValue(ann_elem);
|
||||
this->name_ = ann_elem.GetName();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ScalarValue *Value::GetAsScalar()
|
||||
{
|
||||
ASSERT(!IsArray());
|
||||
return static_cast<ScalarValue *>(this);
|
||||
}
|
||||
|
||||
const ScalarValue *Value::GetAsScalar() const
|
||||
{
|
||||
ASSERT(!IsArray());
|
||||
return static_cast<const ScalarValue *>(this);
|
||||
}
|
||||
|
||||
ArrayValue *Value::GetAsArray()
|
||||
{
|
||||
ASSERT(IsArray());
|
||||
return static_cast<ArrayValue *>(this);
|
||||
}
|
||||
|
||||
const ArrayValue *Value::GetAsArray() const
|
||||
{
|
||||
ASSERT(IsArray());
|
||||
return static_cast<const ArrayValue *>(this);
|
||||
}
|
||||
|
||||
/* static */
|
||||
std::string AnnotationElement::TypeToString(Value::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case Value::Type::U1:
|
||||
return "u1";
|
||||
case Value::Type::I8:
|
||||
return "i8";
|
||||
case Value::Type::U8:
|
||||
return "u8";
|
||||
case Value::Type::I16:
|
||||
return "i16";
|
||||
case Value::Type::U16:
|
||||
return "u16";
|
||||
case Value::Type::I32:
|
||||
return "i32";
|
||||
case Value::Type::U32:
|
||||
return "u32";
|
||||
case Value::Type::I64:
|
||||
return "i64";
|
||||
case Value::Type::U64:
|
||||
return "u64";
|
||||
case Value::Type::F32:
|
||||
return "f32";
|
||||
case Value::Type::F64:
|
||||
return "f64";
|
||||
case Value::Type::STRING:
|
||||
return "string";
|
||||
case Value::Type::RECORD:
|
||||
return "record";
|
||||
case Value::Type::METHOD:
|
||||
return "method";
|
||||
case Value::Type::ENUM:
|
||||
return "enum";
|
||||
case Value::Type::ANNOTATION:
|
||||
return "annotation";
|
||||
case Value::Type::ARRAY:
|
||||
return "array";
|
||||
case Value::Type::VOID:
|
||||
return "void";
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
558
static_core/assembler/annotation.h
Normal file
558
static_core/assembler/annotation.h
Normal file
@ -0,0 +1,558 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_ASSEMBLER_ANNOTATION_H_
|
||||
#define PANDA_ASSEMBLER_ANNOTATION_H_
|
||||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "assembly-type.h"
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
class AnnotationElement;
|
||||
|
||||
class AnnotationData {
|
||||
public:
|
||||
AnnotationData(std::string_view record_name, std::vector<AnnotationElement> elements)
|
||||
: record_name_(record_name), elements_(std::move(elements))
|
||||
{
|
||||
}
|
||||
|
||||
explicit AnnotationData(std::string_view record_name) : record_name_(record_name) {}
|
||||
|
||||
DEFAULT_MOVE_SEMANTIC(AnnotationData);
|
||||
DEFAULT_COPY_SEMANTIC(AnnotationData);
|
||||
|
||||
~AnnotationData() = default;
|
||||
|
||||
std::string GetName() const
|
||||
{
|
||||
return record_name_;
|
||||
}
|
||||
|
||||
const std::vector<AnnotationElement> &GetElements() const
|
||||
{
|
||||
return elements_;
|
||||
}
|
||||
|
||||
void AddElement(AnnotationElement &&element)
|
||||
{
|
||||
elements_.push_back(std::forward<AnnotationElement>(element));
|
||||
}
|
||||
|
||||
private:
|
||||
std::string record_name_;
|
||||
std::vector<AnnotationElement> elements_;
|
||||
};
|
||||
|
||||
class ScalarValue;
|
||||
class ArrayValue;
|
||||
|
||||
class Value {
|
||||
public:
|
||||
enum class Type {
|
||||
U1,
|
||||
I8,
|
||||
U8,
|
||||
I16,
|
||||
U16,
|
||||
I32,
|
||||
U32,
|
||||
I64,
|
||||
U64,
|
||||
F32,
|
||||
F64,
|
||||
STRING,
|
||||
STRING_NULLPTR,
|
||||
RECORD,
|
||||
METHOD,
|
||||
ENUM,
|
||||
ANNOTATION,
|
||||
ARRAY,
|
||||
VOID,
|
||||
METHOD_HANDLE,
|
||||
UNKNOWN
|
||||
};
|
||||
|
||||
static constexpr char GetTypeAsChar(Type t)
|
||||
{
|
||||
char type = '0';
|
||||
switch (t) {
|
||||
case Type::U1:
|
||||
type = '1';
|
||||
break;
|
||||
case Type::I8:
|
||||
type = '2';
|
||||
break;
|
||||
case Type::U8:
|
||||
type = '3';
|
||||
break;
|
||||
case Type::I16:
|
||||
type = '4';
|
||||
break;
|
||||
case Type::U16:
|
||||
type = '5';
|
||||
break;
|
||||
case Type::I32:
|
||||
type = '6';
|
||||
break;
|
||||
case Type::U32:
|
||||
type = '7';
|
||||
break;
|
||||
case Type::I64:
|
||||
type = '8';
|
||||
break;
|
||||
case Type::U64:
|
||||
type = '9';
|
||||
break;
|
||||
case Type::F32:
|
||||
type = 'A';
|
||||
break;
|
||||
case Type::F64:
|
||||
type = 'B';
|
||||
break;
|
||||
case Type::STRING:
|
||||
type = 'C';
|
||||
break;
|
||||
case Type::RECORD:
|
||||
type = 'D';
|
||||
break;
|
||||
case Type::METHOD:
|
||||
type = 'E';
|
||||
break;
|
||||
case Type::ENUM:
|
||||
type = 'F';
|
||||
break;
|
||||
case Type::ANNOTATION:
|
||||
type = 'G';
|
||||
break;
|
||||
case Type::ARRAY:
|
||||
type = 'H';
|
||||
break;
|
||||
case Type::VOID:
|
||||
type = 'I';
|
||||
break;
|
||||
case Type::METHOD_HANDLE:
|
||||
type = 'J';
|
||||
break;
|
||||
case Type::STRING_NULLPTR:
|
||||
type = '*';
|
||||
break;
|
||||
case Type::UNKNOWN:
|
||||
default:
|
||||
type = '0';
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
static constexpr char GetArrayTypeAsChar(Type t)
|
||||
{
|
||||
char type = '0';
|
||||
switch (t) {
|
||||
case Type::U1:
|
||||
type = 'K';
|
||||
break;
|
||||
case Type::I8:
|
||||
type = 'L';
|
||||
break;
|
||||
case Type::U8:
|
||||
type = 'M';
|
||||
break;
|
||||
case Type::I16:
|
||||
type = 'N';
|
||||
break;
|
||||
case Type::U16:
|
||||
type = 'O';
|
||||
break;
|
||||
case Type::I32:
|
||||
type = 'P';
|
||||
break;
|
||||
case Type::U32:
|
||||
type = 'Q';
|
||||
break;
|
||||
case Type::I64:
|
||||
type = 'R';
|
||||
break;
|
||||
case Type::U64:
|
||||
type = 'S';
|
||||
break;
|
||||
case Type::F32:
|
||||
type = 'T';
|
||||
break;
|
||||
case Type::F64:
|
||||
type = 'U';
|
||||
break;
|
||||
case Type::STRING:
|
||||
type = 'V';
|
||||
break;
|
||||
case Type::RECORD:
|
||||
type = 'W';
|
||||
break;
|
||||
case Type::METHOD:
|
||||
type = 'X';
|
||||
break;
|
||||
case Type::ENUM:
|
||||
type = 'Y';
|
||||
break;
|
||||
case Type::ANNOTATION:
|
||||
type = 'Z';
|
||||
break;
|
||||
case Type::METHOD_HANDLE:
|
||||
type = '@';
|
||||
break;
|
||||
case Type::UNKNOWN:
|
||||
default:
|
||||
type = '0';
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
static constexpr Type GetCharAsType(char c)
|
||||
{
|
||||
Type type = Type::UNKNOWN;
|
||||
switch (c) {
|
||||
case '1':
|
||||
type = Type::U1;
|
||||
break;
|
||||
case '2':
|
||||
type = Type::I8;
|
||||
break;
|
||||
case '3':
|
||||
type = Type::U8;
|
||||
break;
|
||||
case '4':
|
||||
type = Type::I16;
|
||||
break;
|
||||
case '5':
|
||||
type = Type::U16;
|
||||
break;
|
||||
case '6':
|
||||
type = Type::I32;
|
||||
break;
|
||||
case '7':
|
||||
type = Type::U32;
|
||||
break;
|
||||
case '8':
|
||||
type = Type::I64;
|
||||
break;
|
||||
case '9':
|
||||
type = Type::U64;
|
||||
break;
|
||||
case 'A':
|
||||
type = Type::F32;
|
||||
break;
|
||||
case 'B':
|
||||
type = Type::F64;
|
||||
break;
|
||||
case 'C':
|
||||
type = Type::STRING;
|
||||
break;
|
||||
case 'D':
|
||||
type = Type::RECORD;
|
||||
break;
|
||||
case 'E':
|
||||
type = Type::METHOD;
|
||||
break;
|
||||
case 'F':
|
||||
type = Type::ENUM;
|
||||
break;
|
||||
case 'G':
|
||||
type = Type::ANNOTATION;
|
||||
break;
|
||||
case 'H':
|
||||
type = Type::ARRAY;
|
||||
break;
|
||||
case 'I':
|
||||
type = Type::VOID;
|
||||
break;
|
||||
case 'J':
|
||||
type = Type::METHOD_HANDLE;
|
||||
break;
|
||||
case '*':
|
||||
type = Type::STRING_NULLPTR;
|
||||
break;
|
||||
case '0':
|
||||
default:
|
||||
type = Type::UNKNOWN;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
static constexpr Type GetCharAsArrayType(char c)
|
||||
{
|
||||
Type type = Type::UNKNOWN;
|
||||
switch (c) {
|
||||
case 'K':
|
||||
type = Type::U1;
|
||||
break;
|
||||
case 'L':
|
||||
type = Type::I8;
|
||||
break;
|
||||
case 'M':
|
||||
type = Type::U8;
|
||||
break;
|
||||
case 'N':
|
||||
type = Type::I16;
|
||||
break;
|
||||
case 'O':
|
||||
type = Type::U16;
|
||||
break;
|
||||
case 'P':
|
||||
type = Type::I32;
|
||||
break;
|
||||
case 'Q':
|
||||
type = Type::U32;
|
||||
break;
|
||||
case 'R':
|
||||
type = Type::I64;
|
||||
break;
|
||||
case 'S':
|
||||
type = Type::U64;
|
||||
break;
|
||||
case 'T':
|
||||
type = Type::F32;
|
||||
break;
|
||||
case 'U':
|
||||
type = Type::F64;
|
||||
break;
|
||||
case 'V':
|
||||
type = Type::STRING;
|
||||
break;
|
||||
case 'W':
|
||||
type = Type::RECORD;
|
||||
break;
|
||||
case 'X':
|
||||
type = Type::METHOD;
|
||||
break;
|
||||
case 'Y':
|
||||
type = Type::ENUM;
|
||||
break;
|
||||
case 'Z':
|
||||
type = Type::ANNOTATION;
|
||||
break;
|
||||
case '@':
|
||||
type = Type::METHOD_HANDLE;
|
||||
break;
|
||||
case '0':
|
||||
default:
|
||||
type = Type::UNKNOWN;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
Type GetType() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
bool IsArray() const
|
||||
{
|
||||
return type_ == Type::ARRAY;
|
||||
}
|
||||
|
||||
PANDA_PUBLIC_API ScalarValue *GetAsScalar();
|
||||
|
||||
PANDA_PUBLIC_API const ScalarValue *GetAsScalar() const;
|
||||
|
||||
PANDA_PUBLIC_API ArrayValue *GetAsArray();
|
||||
|
||||
PANDA_PUBLIC_API const ArrayValue *GetAsArray() const;
|
||||
|
||||
virtual ~Value() = default;
|
||||
|
||||
DEFAULT_COPY_SEMANTIC(Value);
|
||||
DEFAULT_MOVE_SEMANTIC(Value);
|
||||
|
||||
protected:
|
||||
explicit Value(Type type) : type_(type) {}
|
||||
|
||||
private:
|
||||
Type type_;
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
|
||||
template <Value::Type VALUE_TYPE>
|
||||
struct ValueTypeHelper {
|
||||
// Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=40640
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
using Type = std::conditional_t<VALUE_TYPE == Value::Type::U1, uint8_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::I8, int8_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::U8, uint8_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::I16, int16_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::U16, uint16_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::I32, int32_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::U32, uint32_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::I64, int64_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::U64, uint64_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::F32, float,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::F64, double,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::STRING, std::string_view,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::STRING_NULLPTR, uint32_t,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::RECORD, pandasm::Type,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::METHOD, std::string_view,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::ENUM, std::string_view,
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
std::conditional_t<VALUE_TYPE == Value::Type::ANNOTATION, AnnotationData,
|
||||
void>>>>>>>>>>>>>>>>>;
|
||||
};
|
||||
|
||||
// clang-format on
|
||||
|
||||
template <Value::Type TYPE>
|
||||
using ValueTypeHelperT = typename ValueTypeHelper<TYPE>::Type;
|
||||
|
||||
class ScalarValue : public Value {
|
||||
public:
|
||||
template <Value::Type TYPE>
|
||||
// Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=40640
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
static ScalarValue Create(ValueTypeHelperT<TYPE> value)
|
||||
{
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
using T = ValueTypeHelperT<TYPE>;
|
||||
// Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
|
||||
// NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
|
||||
if constexpr (std::is_integral_v<T>) { // NOLINT(bugprone-suspicious-semicolon)
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
return ScalarValue(TYPE, static_cast<uint64_t>(value));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
|
||||
if constexpr (!std::is_integral_v<T>) { // NOLINT(bugprone-suspicious-semicolon)
|
||||
// NOLINTNEXTLINE(readability-magic-numbers)
|
||||
return ScalarValue(TYPE, value);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T GetValue() const
|
||||
{
|
||||
// Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203
|
||||
// NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
|
||||
if constexpr (std::is_integral_v<T>) { // NOLINT(bugprone-suspicious-semicolon)
|
||||
return static_cast<T>(std::get<uint64_t>(value_));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements)
|
||||
if constexpr (!std::is_integral_v<T>) { // NOLINT(bugprone-suspicious-semicolon)
|
||||
return std::get<T>(value_);
|
||||
}
|
||||
}
|
||||
|
||||
DEFAULT_MOVE_SEMANTIC(ScalarValue);
|
||||
DEFAULT_COPY_SEMANTIC(ScalarValue);
|
||||
|
||||
~ScalarValue() override = default;
|
||||
|
||||
private:
|
||||
ScalarValue(Type type, uint64_t value) : Value(type), value_(value) {}
|
||||
|
||||
ScalarValue(Type type, float value) : Value(type), value_(value) {}
|
||||
|
||||
ScalarValue(Type type, double value) : Value(type), value_(value) {}
|
||||
|
||||
ScalarValue(Type type, std::string_view value) : Value(type), value_(std::string(value)) {}
|
||||
|
||||
ScalarValue(Type type, pandasm::Type value) : Value(type), value_(std::move(value)) {}
|
||||
|
||||
ScalarValue(Type type, AnnotationData &value) : Value(type), value_(value) {}
|
||||
|
||||
std::variant<uint64_t, float, double, std::string, pandasm::Type, AnnotationData> value_;
|
||||
};
|
||||
|
||||
class ArrayValue : public Value {
|
||||
public:
|
||||
ArrayValue(Type component_type, std::vector<ScalarValue> values)
|
||||
: Value(Type::ARRAY), component_type_(component_type), values_(std::move(values))
|
||||
{
|
||||
}
|
||||
|
||||
DEFAULT_MOVE_SEMANTIC(ArrayValue);
|
||||
DEFAULT_COPY_SEMANTIC(ArrayValue);
|
||||
|
||||
~ArrayValue() override = default;
|
||||
|
||||
const std::vector<ScalarValue> &GetValues() const
|
||||
{
|
||||
return values_;
|
||||
}
|
||||
|
||||
Type GetComponentType() const
|
||||
{
|
||||
return component_type_;
|
||||
}
|
||||
|
||||
private:
|
||||
Type component_type_;
|
||||
std::vector<ScalarValue> values_;
|
||||
};
|
||||
|
||||
class AnnotationElement {
|
||||
public:
|
||||
PANDA_PUBLIC_API AnnotationElement(std::string_view name, std::unique_ptr<Value> value)
|
||||
: name_(name), value_(std::move(value))
|
||||
{
|
||||
}
|
||||
|
||||
PANDA_PUBLIC_API AnnotationElement(const AnnotationElement &ann_elem);
|
||||
PANDA_PUBLIC_API AnnotationElement &operator=(const AnnotationElement &ann_elem);
|
||||
DEFAULT_MOVE_SEMANTIC(AnnotationElement);
|
||||
~AnnotationElement() = default;
|
||||
|
||||
std::string GetName() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
Value *GetValue() const
|
||||
{
|
||||
return value_.get();
|
||||
}
|
||||
|
||||
PANDA_PUBLIC_API static std::string TypeToString(Value::Type type);
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::unique_ptr<Value> value_;
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_ANNOTATION_H_
|
103
static_core/assembler/asm_isapi.rb
Executable file
103
static_core/assembler/asm_isapi.rb
Executable file
@ -0,0 +1,103 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# Assembler specific extension of ISAPI
|
||||
Instruction.class_eval do
|
||||
def asm_token
|
||||
mnemonic.tr('.', '_').upcase
|
||||
end
|
||||
|
||||
def call?
|
||||
properties.include?('call')
|
||||
end
|
||||
|
||||
def range?
|
||||
mnemonic.split('.')[-1] == 'range'
|
||||
end
|
||||
|
||||
def simple_call?
|
||||
call? && !range? && !properties.include?('dynamic')
|
||||
end
|
||||
|
||||
def return?
|
||||
stripped_mnemonic == 'return'
|
||||
end
|
||||
|
||||
def return_obj?
|
||||
mnemonic == 'return.obj'
|
||||
end
|
||||
|
||||
def return64?
|
||||
mnemonic == 'return.64'
|
||||
end
|
||||
|
||||
def return32?
|
||||
mnemonic == 'return'
|
||||
end
|
||||
|
||||
def return_void?
|
||||
mnemonic == 'return.void'
|
||||
end
|
||||
end
|
||||
|
||||
def bit_cast(what, to_type, from_type)
|
||||
"bit_cast<#{to_type}, #{from_type}>(static_cast<#{from_type}>(std::get<double>(#{what})))"
|
||||
end
|
||||
|
||||
def index_of_max(a)
|
||||
a.each_with_index.max[1] # returns index of `last` max value
|
||||
end
|
||||
|
||||
def max_number_of_src_regs
|
||||
Panda::instructions.map do |insn|
|
||||
insn.operands.select(&:reg?).select(&:src?).size
|
||||
end.max
|
||||
end
|
||||
|
||||
IR = Struct.new(:opcode, :flags, :dst_idx, :use_idxs)
|
||||
|
||||
module Panda
|
||||
def self.pseudo_instructions
|
||||
insns = []
|
||||
insns << IR.new('MOVX', ['InstFlags::PSEUDO'], 0, [1])
|
||||
insns << IR.new('LDAX', ['InstFlags::PSEUDO', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', [0])
|
||||
insns << IR.new('STAX', ['InstFlags::PSEUDO', 'InstFlags::ACC_READ'], 0, [])
|
||||
insns << IR.new('NEWX', ['InstFlags::PSEUDO'], 0, [])
|
||||
insns << IR.new('INITOBJX', ['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', [])
|
||||
insns << IR.new('CALLX', ['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', [])
|
||||
insns << IR.new('CALLX_VIRT', ['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', [])
|
||||
insns << IR.new('B_P_CALLIX', ['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', [])
|
||||
insns << IR.new('B_P_CALLIEX',['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', [])
|
||||
insns
|
||||
end
|
||||
end
|
||||
|
||||
# returns array of OpenStruct with fields
|
||||
# name - name of variable in emitter code
|
||||
# type - type of variable in emitter code
|
||||
def assembler_signature(group, is_jump)
|
||||
insn = group.first
|
||||
format_ops(insn.format).select { |o| o.name != 'prof'}.each do |o|
|
||||
if o.name.start_with?('imm')
|
||||
if insn.asm_token.start_with?('F')
|
||||
o.type, o.name = is_jump ? ['const std::string &', 'label'] : ['double', o.name]
|
||||
else
|
||||
o.type, o.name = is_jump ? ['const std::string &', 'label'] : ['int64_t', o.name]
|
||||
end
|
||||
elsif o.name.start_with?('id')
|
||||
o.type, o.name = ['const std::string &', 'id']
|
||||
else
|
||||
o.type = 'uint16_t'
|
||||
end
|
||||
end
|
||||
end
|
249
static_core/assembler/asm_metadata.rb
Executable file
249
static_core/assembler/asm_metadata.rb
Executable file
@ -0,0 +1,249 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
require 'ostruct'
|
||||
require 'delegate'
|
||||
|
||||
class Attritute < SimpleDelegator
|
||||
def getter_name
|
||||
r = name.capitalize
|
||||
type == 'bool' ? 'Is' + r : 'Get' + r
|
||||
end
|
||||
|
||||
def setter_name
|
||||
'Set' + name.capitalize
|
||||
end
|
||||
|
||||
def bool?
|
||||
type == 'bool'
|
||||
end
|
||||
|
||||
def enum?
|
||||
type == 'enum'
|
||||
end
|
||||
|
||||
def size?
|
||||
type == 'size'
|
||||
end
|
||||
|
||||
def multiple?
|
||||
!bool? && multiple
|
||||
end
|
||||
|
||||
def applicable_to?(item_type)
|
||||
applicable_to.include?(item_type)
|
||||
end
|
||||
|
||||
def set_flags?
|
||||
(defined? flags) && flags.any? || enum? && values.any? { |v| v.flags && v.flags.any? }
|
||||
end
|
||||
end
|
||||
|
||||
module Metadata
|
||||
module_function
|
||||
|
||||
def attributes
|
||||
@data.attributes.map do |op|
|
||||
Attritute.new(op)
|
||||
end
|
||||
end
|
||||
|
||||
def language
|
||||
@data.language || ''
|
||||
end
|
||||
|
||||
def extends_default?
|
||||
!language.empty?
|
||||
end
|
||||
|
||||
def item_types
|
||||
['record', 'field', 'function', 'param']
|
||||
end
|
||||
|
||||
def wrap_data(data)
|
||||
@data = data
|
||||
end
|
||||
end
|
||||
|
||||
def Gen.on_require(data)
|
||||
Metadata.wrap_data(data)
|
||||
end
|
||||
|
||||
module MetadataGen
|
||||
module_function
|
||||
|
||||
def attribute_name(attribute)
|
||||
return attribute.name if Metadata.language.empty?
|
||||
"#{Metadata.language.downcase}.#{attribute.name}"
|
||||
end
|
||||
|
||||
def class_name(item_type)
|
||||
item_type.capitalize + 'Metadata'
|
||||
end
|
||||
|
||||
def validate_body(item_type, is_bool)
|
||||
attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool }
|
||||
body = []
|
||||
indent = ' ' * 4
|
||||
|
||||
attributes.each do |a|
|
||||
body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {"
|
||||
|
||||
unless a.multiple?
|
||||
body << "#{indent * 2}if (HasAttribute(attribute)) {"
|
||||
body << "#{indent * 3}return Error(\"Attribute '#{attribute_name(a)}' already defined\","
|
||||
body << "#{indent * 3} Error::Type::MULTIPLE_ATTRIBUTE);"
|
||||
body << "#{indent * 2}}"
|
||||
end
|
||||
|
||||
if a.enum?
|
||||
a.values.each do |v|
|
||||
body << "#{indent * 2}if (value == \"#{v.value}\") {"
|
||||
body << "#{indent * 3}return {};"
|
||||
body << "#{indent * 2}}"
|
||||
body << ""
|
||||
end
|
||||
|
||||
body << "#{indent * 2}return Error(std::string(\"Attribute '#{attribute_name(a)}' have incorrect value '\").append(value) +"
|
||||
body << "#{indent * 2} R\"('. Should be one of #{a.values.map(&:value)})\", Error::Type::INVALID_VALUE);"
|
||||
elsif a.size?
|
||||
body << "#{indent * 2}return ValidateSize(value);"
|
||||
else
|
||||
body << "#{indent * 2}return {};"
|
||||
end
|
||||
|
||||
body << "#{indent}}"
|
||||
body << ""
|
||||
end
|
||||
|
||||
Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? != is_bool }.each do |a|
|
||||
body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {"
|
||||
body << "#{indent * 2}return Error(\"Attribute '#{attribute_name(a)}' #{is_bool ? "must" : "must not"} have a value\","
|
||||
body << "#{indent * 2} #{is_bool ? "Error::Type::MISSING_VALUE" : "Error::Type::UNEXPECTED_VALUE"});"
|
||||
body << "#{indent}}"
|
||||
body << ""
|
||||
end
|
||||
|
||||
if Metadata::extends_default?
|
||||
args = ['attribute']
|
||||
args << 'value' unless is_bool
|
||||
body << "#{indent}return pandasm::#{class_name(item_type)}::Validate(#{args.join(', ')});"
|
||||
else
|
||||
body << "#{indent}return Error(std::string(\"Unknown attribute '\").append(attribute) + \"'\","
|
||||
body << "#{indent} Error::Type::UNKNOWN_ATTRIBUTE);"
|
||||
end
|
||||
|
||||
body
|
||||
end
|
||||
|
||||
def set_flags_body(item_type, is_bool)
|
||||
attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool && a.set_flags? }
|
||||
body = []
|
||||
indent = ' ' * 4
|
||||
|
||||
attributes.each do |a|
|
||||
body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {"
|
||||
|
||||
if defined? a.flags
|
||||
body << "#{indent * 2}SetAccessFlags(GetAccessFlags() | #{a.flags.join(' | ')});"
|
||||
end
|
||||
|
||||
if a.enum?
|
||||
a.values.select { |v| v.flags && v.flags.any? }.each do |v|
|
||||
body << "#{indent * 2}if (value == \"#{v.value}\") {"
|
||||
body << "#{indent * 3}SetAccessFlags(GetAccessFlags() | #{v.flags.join(' | ')});"
|
||||
body << "#{indent * 2}}"
|
||||
body << ""
|
||||
end
|
||||
end
|
||||
|
||||
body << "#{indent}}"
|
||||
end
|
||||
|
||||
if Metadata::extends_default?
|
||||
args = ['attribute']
|
||||
args << 'value' unless is_bool
|
||||
body << "#{indent}pandasm::#{class_name(item_type)}::SetFlags(#{args.join(', ')});"
|
||||
end
|
||||
|
||||
body
|
||||
end
|
||||
|
||||
def remove_flags_body(item_type, is_bool)
|
||||
attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool && a.set_flags? }
|
||||
body = []
|
||||
indent = ' ' * 4
|
||||
|
||||
attributes.each do |a|
|
||||
body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {"
|
||||
|
||||
if defined? a.flags
|
||||
body << "#{indent * 2}if ((GetAccessFlags() & #{a.flags.join(' | ')}) != 0) {"
|
||||
body << "#{indent * 3}SetAccessFlags(GetAccessFlags() ^ (#{a.flags.join(' | ')}));"
|
||||
body << "#{indent * 2}}"
|
||||
end
|
||||
|
||||
if a.enum?
|
||||
a.values.select { |v| v.flags && v.flags.any? }.each do |v|
|
||||
body << "#{indent * 2}if (value == \"#{v.value}\") {"
|
||||
body << "#{indent * 3}if ((GetAccessFlags() & (#{v.flags.join(' | ')})) != 0) {"
|
||||
body << "#{indent * 4}SetAccessFlags(GetAccessFlags() ^ (#{v.flags.join(' | ')}));"
|
||||
body << "#{indent * 3}}"
|
||||
body << "#{indent * 2}}"
|
||||
end
|
||||
end
|
||||
|
||||
body << "#{indent}}"
|
||||
end
|
||||
|
||||
if Metadata::extends_default?
|
||||
args = ['attribute']
|
||||
args << 'value' unless is_bool
|
||||
body << "#{indent}pandasm::#{class_name(item_type)}::RemoveFlags(#{args.join(', ')});"
|
||||
end
|
||||
|
||||
body
|
||||
end
|
||||
|
||||
def arg_list(is_bool)
|
||||
args = ['std::string_view attribute']
|
||||
args << 'std::string_view value' if !is_bool
|
||||
args
|
||||
end
|
||||
|
||||
def add_unused_attribute(arg)
|
||||
"[[maybe_unused]] #{arg}"
|
||||
end
|
||||
|
||||
def validate_arg_list(item_type, is_bool)
|
||||
args = arg_list(is_bool)
|
||||
return args if Metadata::extends_default?
|
||||
|
||||
attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool }
|
||||
args[0] = add_unused_attribute(args[0]) if attributes.none?
|
||||
args[1] = add_unused_attribute(args[1]) if args[1] && attributes.none? { |a| a.enum? }
|
||||
args
|
||||
end
|
||||
|
||||
def flags_arg_list(item_type, is_bool)
|
||||
args = arg_list(is_bool)
|
||||
return args if Metadata::extends_default?
|
||||
|
||||
attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool && a.set_flags? }
|
||||
use_value = attributes.any? { |a| a.enum? && a.values.any? { |v| v.flags && v.flags.any? } }
|
||||
args[0] = add_unused_attribute(args[0]) if attributes.none?
|
||||
args[1] = add_unused_attribute(args[1]) if args[1] && !use_value
|
||||
args
|
||||
end
|
||||
|
||||
end
|
80
static_core/assembler/assembly-context.h
Normal file
80
static_core/assembler/assembly-context.h
Normal file
@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_CONTEXT_HPP
|
||||
#define _PANDA_ASSEMBLER_CONTEXT_HPP
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "assembly-ins.h"
|
||||
#include "assembly-type.h"
|
||||
#include "error.h"
|
||||
#include "lexer.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
// NOLINTBEGIN(misc-non-private-member-variables-in-classes)
|
||||
/*
|
||||
* Used to move around tokens.
|
||||
* *context :
|
||||
* Returns current value of a token
|
||||
* ++context :
|
||||
* sets the next token value
|
||||
* returns current value of a token
|
||||
* context++ :
|
||||
* sets the next token value
|
||||
* returns the next value of a token
|
||||
* similarly --context and context--
|
||||
*/
|
||||
struct Context {
|
||||
std::string_view token; /* current token */
|
||||
std::vector<panda::pandasm::Token> tokens; /* token list */
|
||||
size_t number = 0; /* line number */
|
||||
bool end = false; /* end of line flag */
|
||||
Token::Type id = Token::Type::ID_BAD; /* current token type */
|
||||
Token::Type signop = Token::Type::ID_BAD; /* current token operand type (if it is an operation) */
|
||||
panda::pandasm::Error err; /* current error */
|
||||
int64_t *max_value_of_reg = nullptr;
|
||||
size_t ins_number = 0;
|
||||
Type curr_func_return_type;
|
||||
std::vector<std::pair<size_t, size_t>> *function_arguments_list = nullptr;
|
||||
std::unordered_map<std::string, std::vector<std::pair<size_t, size_t>>> function_arguments_lists;
|
||||
|
||||
void Make(const std::vector<panda::pandasm::Token> &t);
|
||||
void UpSignOperation();
|
||||
bool ValidateRegisterName(char c, size_t n = 0) const;
|
||||
bool ValidateParameterName(size_t number_of_params_already_is) const;
|
||||
bool ValidateLabel();
|
||||
bool Mask();
|
||||
bool NextMask();
|
||||
size_t Len() const;
|
||||
std::string_view GiveToken();
|
||||
Token::Type WaitFor();
|
||||
Token::Type Next();
|
||||
|
||||
Token::Type operator++(int); // NOLINT(cert-dcl21-cpp)
|
||||
Token::Type operator--(int); // NOLINT(cert-dcl21-cpp)
|
||||
Token::Type operator++();
|
||||
Token::Type operator--();
|
||||
Token::Type operator*();
|
||||
};
|
||||
// NOLINTEND(misc-non-private-member-variables-in-classes)
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_CONTEXT_HPP
|
60
static_core/assembler/assembly-debug.h
Normal file
60
static_core/assembler/assembly-debug.h
Normal file
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLY_DEBUG_H
|
||||
#define _PANDA_ASSEMBLY_DEBUG_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace panda::pandasm::debuginfo {
|
||||
|
||||
// NOLINTBEGIN(misc-non-private-member-variables-in-classes)
|
||||
struct Ins {
|
||||
size_t line_number = 0;
|
||||
uint32_t column_number = 0;
|
||||
std::string whole_line; // TODO(mbolshov): redundant given file and line_number
|
||||
size_t bound_left = 0;
|
||||
size_t bound_right = 0;
|
||||
|
||||
void SetLineNumber(size_t ln)
|
||||
{
|
||||
line_number = ln;
|
||||
}
|
||||
|
||||
void SetColumnNumber(size_t cn)
|
||||
{
|
||||
column_number = cn;
|
||||
}
|
||||
|
||||
Ins() = default;
|
||||
Ins(size_t l_n, std::string &f_c, size_t b_l, size_t b_r)
|
||||
: line_number(l_n), whole_line(std::move(f_c)), bound_left(b_l), bound_right(b_r)
|
||||
{
|
||||
}
|
||||
};
|
||||
// NOLINTEND(misc-non-private-member-variables-in-classes)
|
||||
|
||||
struct LocalVariable {
|
||||
std::string name;
|
||||
std::string signature;
|
||||
std::string signature_type;
|
||||
int32_t reg = 0;
|
||||
uint32_t start = 0;
|
||||
uint32_t length = 0;
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm::debuginfo
|
||||
|
||||
#endif // !_PANDA_ASSEMBLY_DEBUG_H
|
1941
static_core/assembler/assembly-emitter.cpp
Normal file
1941
static_core/assembler/assembly-emitter.cpp
Normal file
File diff suppressed because it is too large
Load Diff
252
static_core/assembler/assembly-emitter.h
Normal file
252
static_core/assembler/assembly-emitter.h
Normal file
@ -0,0 +1,252 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_EMITTER_HPP
|
||||
#define _PANDA_ASSEMBLER_EMITTER_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "assembly-ins.h"
|
||||
#include "assembly-literals.h"
|
||||
#include "assembly-program.h"
|
||||
#include "assembly-type.h"
|
||||
#include "assembly-function.h"
|
||||
#include "bytecode_emitter.h"
|
||||
#include "file_item_container.h"
|
||||
#include "pgo.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
class AsmEmitter {
|
||||
public:
|
||||
struct PandaFileToPandaAsmMaps {
|
||||
std::unordered_map<uint32_t, std::string> methods;
|
||||
std::unordered_map<uint32_t, std::string> fields;
|
||||
std::unordered_map<uint32_t, std::string> classes;
|
||||
std::unordered_map<uint32_t, std::string> strings;
|
||||
std::unordered_map<uint32_t, std::string> literalarrays;
|
||||
};
|
||||
|
||||
struct AsmEntityCollections {
|
||||
std::unordered_map<std::string, panda_file::BaseMethodItem *> method_items;
|
||||
std::unordered_map<std::string, panda_file::BaseFieldItem *> field_items;
|
||||
std::unordered_map<std::string, panda_file::BaseClassItem *> class_items;
|
||||
std::unordered_map<std::string_view, panda_file::StringItem *> string_items;
|
||||
std::unordered_map<std::string, panda_file::LiteralArrayItem *> literalarray_items;
|
||||
};
|
||||
|
||||
PANDA_PUBLIC_API static bool Emit(panda_file::ItemContainer *items, const Program &program,
|
||||
PandaFileToPandaAsmMaps *maps = nullptr, bool emit_debug_info = true,
|
||||
panda::panda_file::pgo::ProfileOptimizer *profile_opt = nullptr);
|
||||
|
||||
PANDA_PUBLIC_API static bool Emit(panda_file::Writer *writer, const Program &program,
|
||||
std::map<std::string, size_t> *stat = nullptr,
|
||||
PandaFileToPandaAsmMaps *maps = nullptr, bool debug_info = true,
|
||||
panda::panda_file::pgo::ProfileOptimizer *profile_opt = nullptr);
|
||||
|
||||
PANDA_PUBLIC_API static bool Emit(const std::string &filename, const Program &program,
|
||||
std::map<std::string, size_t> *stat = nullptr,
|
||||
PandaFileToPandaAsmMaps *maps = nullptr, bool debug_info = true,
|
||||
panda::panda_file::pgo::ProfileOptimizer *profile_opt = nullptr);
|
||||
|
||||
PANDA_PUBLIC_API static std::unique_ptr<const panda_file::File> Emit(const Program &program,
|
||||
PandaFileToPandaAsmMaps *maps = nullptr);
|
||||
|
||||
PANDA_PUBLIC_API static bool AssignProfileInfo(Program *program);
|
||||
|
||||
PANDA_PUBLIC_API static std::string GetLastError()
|
||||
{
|
||||
return last_error_;
|
||||
}
|
||||
|
||||
private:
|
||||
static void MakeStringItems(panda_file::ItemContainer *items, const Program &program,
|
||||
AsmEntityCollections &entities);
|
||||
static void MakeLiteralItems(panda_file::ItemContainer *items, const Program &program,
|
||||
AsmEmitter::AsmEntityCollections &entities);
|
||||
static void MakeArrayTypeItems(panda_file::ItemContainer *items, const Program &program,
|
||||
AsmEntityCollections &entities);
|
||||
static bool HandleRecordAsForeign(
|
||||
panda_file::ItemContainer *items, const Program &program, AsmEntityCollections &entities,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types,
|
||||
const std::string &name, const Record &rec);
|
||||
static bool HandleBaseRecord(panda_file::ItemContainer *items, const Program &program, const std::string &name,
|
||||
const Record &rec, panda_file::ClassItem *record);
|
||||
static bool HandleInterfaces(panda_file::ItemContainer *items, const Program &program, const std::string &name,
|
||||
const Record &rec, panda_file::ClassItem *record);
|
||||
static bool HandleFields(
|
||||
panda_file::ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types,
|
||||
const std::string &name, const Record &rec, panda_file::ClassItem *record);
|
||||
static bool HandleRecord(
|
||||
panda_file::ItemContainer *items, const Program &program, AsmEntityCollections &entities,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types,
|
||||
const std::string &name, const Record &rec);
|
||||
static bool MakeRecordItems(
|
||||
panda_file::ItemContainer *items, const Program &program, AsmEntityCollections &entities,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types);
|
||||
static panda_file::StringItem *GetMethodName(panda_file::ItemContainer *items, const Function &func,
|
||||
const std::string &name);
|
||||
static bool HandleAreaForInner(panda_file::ItemContainer *items, const Program &program,
|
||||
panda_file::ClassItem **area, panda_file::ForeignClassItem **foreign_area,
|
||||
const std::string &name, const std::string &record_owner_name);
|
||||
static bool HandleRecordOnwer(panda_file::ItemContainer *items, const Program &program,
|
||||
panda_file::ClassItem **area, panda_file::ForeignClassItem **foreign_area,
|
||||
const std::string &name, const std::string &record_owner_name);
|
||||
static bool HandleFunctionParams(
|
||||
panda_file::ItemContainer *items, const Program &program, size_t idx, const std::string &name,
|
||||
const Function &func,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types,
|
||||
std::vector<panda_file::MethodParamItem> ¶ms);
|
||||
static bool HandleFunctionLocalVariables(panda_file::ItemContainer *items, const Function &func,
|
||||
const std::string &name);
|
||||
static bool CreateMethodItem(panda_file::ItemContainer *items, AsmEmitter::AsmEntityCollections &entities,
|
||||
const Function &func, panda_file::TypeItem *type_item, panda_file::ClassItem *area,
|
||||
panda_file::ForeignClassItem *foreign_area, uint32_t access_flags,
|
||||
panda_file::StringItem *method_name, const std::string &mangled_name,
|
||||
const std::string &name, std::vector<panda_file::MethodParamItem> ¶ms);
|
||||
static bool MakeFunctionItems(
|
||||
panda_file::ItemContainer *items, const Program &program, AsmEntityCollections &entities,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types,
|
||||
bool emit_debug_info);
|
||||
static bool MakeRecordAnnotations(panda_file::ItemContainer *items, const Program &program,
|
||||
const AsmEntityCollections &entities);
|
||||
static void SetCodeAndDebugInfo(panda_file::ItemContainer *items, panda_file::MethodItem *method,
|
||||
const Function &func, bool emit_debug_info);
|
||||
static void SetMethodSourceLang(const Program &program, panda_file::MethodItem *method, const Function &func,
|
||||
const std::string &name);
|
||||
static bool AddMethodAndParamsAnnotations(panda_file::ItemContainer *items, const Program &program,
|
||||
const AsmEmitter::AsmEntityCollections &entities,
|
||||
panda_file::MethodItem *method, const Function &func);
|
||||
static bool MakeFunctionDebugInfoAndAnnotations(panda_file::ItemContainer *items, const Program &program,
|
||||
const AsmEntityCollections &entities, bool emit_debug_info);
|
||||
static void FillMap(PandaFileToPandaAsmMaps *maps, AsmEntityCollections &entities);
|
||||
static void EmitDebugInfo(panda_file::ItemContainer *items, const Program &program,
|
||||
const std::vector<uint8_t> *bytes, const panda_file::MethodItem *method,
|
||||
const Function &func, const std::string &name, bool emit_debug_info);
|
||||
static bool EmitFunctions(panda_file::ItemContainer *items, const Program &program,
|
||||
const AsmEntityCollections &entities, bool emit_debug_info);
|
||||
|
||||
static panda_file::TypeItem *GetTypeItem(
|
||||
panda_file::ItemContainer *items,
|
||||
const std::unordered_map<panda_file::Type::TypeId, panda_file::PrimitiveTypeItem *> &primitive_types,
|
||||
const Type &type, const Program &program);
|
||||
|
||||
PANDA_PUBLIC_API static void SetLastError(const std::string &message)
|
||||
{
|
||||
last_error_ = message;
|
||||
}
|
||||
|
||||
static bool CheckValueType(Value::Type value_type, const Type &type, const Program &program);
|
||||
|
||||
static bool CheckValueEnumCase(const Value *value, const Type &type, const Program &program);
|
||||
static bool CheckValueArrayCase(const Value *value, const Type &type, const Program &program);
|
||||
static bool CheckValueMethodCase(const Value *value, const Program &program);
|
||||
static bool CheckValueRecordCase(const Value *value, const Program &program);
|
||||
static bool CheckValue(const Value *value, const Type &type, const Program &program);
|
||||
static std::string GetMethodSignatureFromProgram(const std::string &name, const Program &program);
|
||||
|
||||
static panda_file::LiteralItem *CreateLiteralItem(
|
||||
panda_file::ItemContainer *container, const Value *value, std::vector<panda_file::LiteralItem> *out,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
template <class PrimType>
|
||||
static panda_file::ScalarValueItem *CreateScalarPrimValueItem(panda_file::ItemContainer *container,
|
||||
const Value *value,
|
||||
std::vector<panda_file::ScalarValueItem> *out)
|
||||
{
|
||||
static_assert(std::is_arithmetic<PrimType>::value);
|
||||
auto v = value->GetAsScalar()->GetValue<PrimType>();
|
||||
if (out != nullptr) {
|
||||
out->emplace_back(v);
|
||||
return &out->back();
|
||||
}
|
||||
|
||||
if constexpr (std::is_same<PrimType, uint32_t>::value) {
|
||||
return container->GetOrCreateIntegerValueItem(v);
|
||||
} else if constexpr (std::is_same<PrimType, uint64_t>::value) {
|
||||
return container->GetOrCreateLongValueItem(v);
|
||||
} else if constexpr (std::is_same<PrimType, float>::value) {
|
||||
return container->GetOrCreateFloatValueItem(v);
|
||||
} else if constexpr (std::is_same<PrimType, double>::value) {
|
||||
return container->GetOrCreateDoubleValueItem(v);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static panda_file::ScalarValueItem *CreateScalarStringValueItem(panda_file::ItemContainer *container,
|
||||
const Value *value,
|
||||
std::vector<panda_file::ScalarValueItem> *out);
|
||||
static panda_file::ScalarValueItem *CreateScalarRecordValueItem(
|
||||
panda_file::ItemContainer *container, const Value *value, std::vector<panda_file::ScalarValueItem> *out,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes);
|
||||
static panda_file::ScalarValueItem *CreateScalarMethodValueItem(
|
||||
panda_file::ItemContainer *container, const Value *value, std::vector<panda_file::ScalarValueItem> *out,
|
||||
const Program &program, const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
static panda_file::ScalarValueItem *CreateScalarEnumValueItem(
|
||||
panda_file::ItemContainer *container, const Value *value, std::vector<panda_file::ScalarValueItem> *out,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields);
|
||||
static panda_file::ScalarValueItem *CreateScalarAnnotationValueItem(
|
||||
panda_file::ItemContainer *container, const Value *value, std::vector<panda_file::ScalarValueItem> *out,
|
||||
const Program &program, const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
static panda_file::ScalarValueItem *CreateScalarValueItem(
|
||||
panda_file::ItemContainer *container, const Value *value, std::vector<panda_file::ScalarValueItem> *out,
|
||||
const Program &program, const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
static panda_file::ValueItem *CreateValueItem(
|
||||
panda_file::ItemContainer *container, const Value *value, const Program &program,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
static panda_file::AnnotationItem *CreateAnnotationItem(
|
||||
panda_file::ItemContainer *container, const AnnotationData &annotation, const Program &program,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
static panda_file::MethodHandleItem *CreateMethodHandleItem(
|
||||
panda_file::ItemContainer *container, const MethodHandle &mh,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
template <class T>
|
||||
static bool AddAnnotations(T *item, panda_file::ItemContainer *container, const AnnotationMetadata &metadata,
|
||||
const Program &program,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods);
|
||||
|
||||
// TODO(mgonopolsky): Refactor to introduce a single error-processing mechanism for parser and emitter
|
||||
// NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
|
||||
PANDA_PUBLIC_API static std::string last_error_;
|
||||
};
|
||||
|
||||
std::string GetOwnerName(std::string name);
|
||||
std::string GetItemName(std::string name);
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_EMITTER_HPP
|
49
static_core/assembler/assembly-field.h
Normal file
49
static_core/assembler/assembly-field.h
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_FIELD_HPP
|
||||
#define _PANDA_ASSEMBLER_FIELD_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "assembly-type.h"
|
||||
#include "extensions/extensions.h"
|
||||
#include "meta.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
// NOLINTBEGIN(misc-non-private-member-variables-in-classes)
|
||||
struct Field {
|
||||
Type type;
|
||||
std::string name;
|
||||
std::unique_ptr<FieldMetadata> metadata;
|
||||
size_t line_of_def = 0;
|
||||
std::string whole_line; /* The line in which the field is defined */
|
||||
/* Or line in which the field met, if the field is not defined */
|
||||
size_t bound_left = 0;
|
||||
size_t bound_right = 0;
|
||||
bool is_defined = true;
|
||||
|
||||
explicit Field(panda::panda_file::SourceLang lang)
|
||||
: metadata(extensions::MetadataExtension::CreateFieldMetadata(lang))
|
||||
{
|
||||
}
|
||||
};
|
||||
// NOLINTEND(misc-non-private-member-variables-in-classes)
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_FIELD_HPP
|
45
static_core/assembler/assembly-file-location.h
Normal file
45
static_core/assembler/assembly-file-location.h
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_FILE_LOCATION_HPP
|
||||
#define _PANDA_ASSEMBLER_FILE_LOCATION_HPP
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
// NOLINTBEGIN(misc-non-private-member-variables-in-classes)
|
||||
class FileLocation {
|
||||
public:
|
||||
std::string whole_line; /* The line in which the field is defined */
|
||||
/* Or line in which the field met, if the field is not defined */
|
||||
size_t bound_left = 0;
|
||||
size_t bound_right = 0;
|
||||
size_t line_number = 0;
|
||||
bool is_defined = false;
|
||||
|
||||
public:
|
||||
FileLocation(std::string &f_c, size_t b_l, size_t b_r, size_t l_n, bool d)
|
||||
: whole_line(std::move(f_c)), bound_left(b_l), bound_right(b_r), line_number(l_n), is_defined(d)
|
||||
{
|
||||
}
|
||||
~FileLocation() = default;
|
||||
|
||||
DEFAULT_MOVE_SEMANTIC(FileLocation);
|
||||
DEFAULT_COPY_SEMANTIC(FileLocation);
|
||||
};
|
||||
// NOLINTEND(misc-non-private-member-variables-in-classes)
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_FILE_INFORMATION
|
192
static_core/assembler/assembly-function.h
Normal file
192
static_core/assembler/assembly-function.h
Normal file
@ -0,0 +1,192 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_FUNCTION_HPP
|
||||
#define _PANDA_ASSEMBLER_FUNCTION_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "assembly-ins.h"
|
||||
#include "assembly-label.h"
|
||||
#include "assembly-type.h"
|
||||
#include "assembly-debug.h"
|
||||
#include "assembly-file-location.h"
|
||||
#include "bytecode_emitter.h"
|
||||
#include "extensions/extensions.h"
|
||||
#include "file_items.h"
|
||||
#include "file_item_container.h"
|
||||
#include "ide_helpers.h"
|
||||
#include "meta.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
// NOLINTBEGIN(misc-non-private-member-variables-in-classes)
|
||||
struct Function {
|
||||
struct CatchBlock {
|
||||
std::string whole_line;
|
||||
std::string exception_record;
|
||||
std::string try_begin_label;
|
||||
std::string try_end_label;
|
||||
std::string catch_begin_label;
|
||||
std::string catch_end_label;
|
||||
};
|
||||
|
||||
struct TryCatchInfo {
|
||||
std::unordered_map<std::string_view, size_t> try_catch_labels;
|
||||
std::unordered_map<std::string, std::vector<const CatchBlock *>> try_catch_map;
|
||||
std::vector<std::string> try_catch_order;
|
||||
TryCatchInfo(std::unordered_map<std::string_view, size_t> &labels,
|
||||
std::unordered_map<std::string, std::vector<const CatchBlock *>> &map,
|
||||
std::vector<std::string> ¶m_try_catch_order)
|
||||
: try_catch_labels(labels), try_catch_map(map), try_catch_order(param_try_catch_order)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct Parameter {
|
||||
Type type;
|
||||
std::unique_ptr<ParamMetadata> metadata;
|
||||
|
||||
Parameter(Type t, panda::panda_file::SourceLang lang)
|
||||
: type(std::move(t)), metadata(extensions::MetadataExtension::CreateParamMetadata(lang))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
std::string name;
|
||||
panda::panda_file::SourceLang language;
|
||||
std::unique_ptr<FunctionMetadata> metadata;
|
||||
|
||||
std::unordered_map<std::string, panda::pandasm::Label> label_table;
|
||||
std::vector<panda::pandasm::Ins> ins; /* function instruction list */
|
||||
std::vector<panda::pandasm::debuginfo::LocalVariable> local_variable_debug;
|
||||
std::string source_file; /* The file in which the function is defined or empty */
|
||||
std::string source_code;
|
||||
std::vector<CatchBlock> catch_blocks;
|
||||
int64_t value_of_first_param = -1;
|
||||
size_t regs_num = 0;
|
||||
size_t profile_size {0};
|
||||
std::vector<Parameter> params;
|
||||
bool body_presence = false;
|
||||
Type return_type;
|
||||
SourceLocation body_location;
|
||||
std::optional<FileLocation> file_location;
|
||||
|
||||
void SetInsDebug(const std::vector<debuginfo::Ins> &ins_debug)
|
||||
{
|
||||
ASSERT(ins_debug.size() == ins.size());
|
||||
for (std::size_t i = 0; i < ins.size(); i++) {
|
||||
ins[i].ins_debug = ins_debug[i];
|
||||
}
|
||||
}
|
||||
|
||||
void AddInstruction(const panda::pandasm::Ins &instruction)
|
||||
{
|
||||
ins.emplace_back(instruction);
|
||||
}
|
||||
|
||||
Function(std::string s, panda::panda_file::SourceLang lang, size_t b_l, size_t b_r, std::string f_c, bool d,
|
||||
size_t l_n)
|
||||
: name(std::move(s)),
|
||||
language(lang),
|
||||
metadata(extensions::MetadataExtension::CreateFunctionMetadata(lang)),
|
||||
file_location({f_c, b_l, b_r, l_n, d})
|
||||
{
|
||||
}
|
||||
|
||||
Function(std::string s, panda::panda_file::SourceLang lang)
|
||||
: name(std::move(s)), language(lang), metadata(extensions::MetadataExtension::CreateFunctionMetadata(lang))
|
||||
{
|
||||
}
|
||||
|
||||
std::size_t GetParamsNum() const
|
||||
{
|
||||
return params.size();
|
||||
}
|
||||
|
||||
std::size_t GetTotalRegs() const
|
||||
{
|
||||
return regs_num;
|
||||
}
|
||||
|
||||
bool IsStatic() const
|
||||
{
|
||||
return (metadata->GetAccessFlags() & ACC_STATIC) != 0;
|
||||
}
|
||||
|
||||
bool Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string_view, panda_file::StringItem *> &strings,
|
||||
const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays) const;
|
||||
|
||||
size_t GetLineNumber(size_t i) const;
|
||||
|
||||
uint32_t GetColumnNumber(size_t i) const;
|
||||
|
||||
void EmitLocalVariable(panda_file::LineNumberProgramItem *program, panda_file::ItemContainer *container,
|
||||
std::vector<uint8_t> *constant_pool, uint32_t &pc_inc, size_t instruction_number) const;
|
||||
void EmitNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool, uint32_t pc_inc,
|
||||
int32_t line_inc) const;
|
||||
void EmitLineNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool,
|
||||
int32_t &prev_line_number, uint32_t &pc_inc, size_t instruction_number) const;
|
||||
|
||||
// column number is only for dynamic language now
|
||||
void EmitColumnNumber(panda_file::LineNumberProgramItem *program, std::vector<uint8_t> *constant_pool,
|
||||
uint32_t &prev_column_number, uint32_t &pc_inc, size_t instruction_number) const;
|
||||
|
||||
void BuildLineNumberProgram(panda_file::DebugInfoItem *debug_item, const std::vector<uint8_t> &bytecode,
|
||||
panda_file::ItemContainer *container, std::vector<uint8_t> *constant_pool,
|
||||
bool emit_debug_info) const;
|
||||
|
||||
Function::TryCatchInfo MakeOrderAndOffsets(const std::vector<uint8_t> &bytecode) const;
|
||||
|
||||
std::vector<panda_file::CodeItem::TryBlock> BuildTryBlocks(
|
||||
panda_file::MethodItem *method, const std::unordered_map<std::string, panda_file::BaseClassItem *> &class_items,
|
||||
const std::vector<uint8_t> &bytecode) const;
|
||||
|
||||
bool HasImplementation() const
|
||||
{
|
||||
return !metadata->IsForeign() && metadata->HasImplementation();
|
||||
}
|
||||
|
||||
bool IsParameter(uint32_t reg_number) const
|
||||
{
|
||||
return reg_number >= regs_num;
|
||||
}
|
||||
|
||||
bool CanThrow() const
|
||||
{
|
||||
return std::any_of(ins.cbegin(), ins.cend(), [](const Ins &insn) { return insn.CanThrow(); });
|
||||
}
|
||||
|
||||
bool HasDebugInfo() const
|
||||
{
|
||||
return std::any_of(ins.cbegin(), ins.cend(), [](const Ins &insn) { return insn.HasDebugInfo(); });
|
||||
}
|
||||
|
||||
void DebugDump() const;
|
||||
};
|
||||
// NOLINTEND(misc-non-private-member-variables-in-classes)
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_FUNCTION_HPP
|
152
static_core/assembler/assembly-ins.cpp
Normal file
152
static_core/assembler/assembly-ins.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "assembly-ins.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
std::string panda::pandasm::Ins::RegsToString(bool &first, bool print_args, size_t first_arg_idx) const
|
||||
{
|
||||
std::stringstream translator;
|
||||
for (const auto ® : this->regs) {
|
||||
if (!first) {
|
||||
translator << ",";
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (print_args && reg >= first_arg_idx) {
|
||||
translator << " a" << reg - first_arg_idx;
|
||||
} else {
|
||||
translator << " v" << reg;
|
||||
}
|
||||
}
|
||||
return translator.str();
|
||||
}
|
||||
|
||||
std::string panda::pandasm::Ins::ImmsToString(bool &first) const
|
||||
{
|
||||
std::stringstream translator;
|
||||
for (const auto &imm : this->imms) {
|
||||
if (!first) {
|
||||
translator << ",";
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
auto *number = std::get_if<double>(&imm);
|
||||
if (number != nullptr) {
|
||||
translator << " " << std::scientific << *number;
|
||||
} else {
|
||||
translator << " 0x" << std::hex << std::get<int64_t>(imm);
|
||||
}
|
||||
translator.clear();
|
||||
}
|
||||
return translator.str();
|
||||
}
|
||||
|
||||
std::string panda::pandasm::Ins::IdsToString(bool &first) const
|
||||
{
|
||||
std::stringstream translator;
|
||||
for (const auto &id : this->ids) {
|
||||
if (!first) {
|
||||
translator << ",";
|
||||
} else {
|
||||
first = false;
|
||||
}
|
||||
|
||||
translator << " " << id;
|
||||
}
|
||||
return translator.str();
|
||||
}
|
||||
|
||||
std::string panda::pandasm::Ins::OperandsToString(bool print_args, size_t first_arg_idx) const
|
||||
{
|
||||
bool first = true;
|
||||
std::stringstream ss {};
|
||||
|
||||
ss << this->RegsToString(first, print_args, first_arg_idx) << this->ImmsToString(first) << this->IdsToString(first);
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
std::string panda::pandasm::Ins::RegToString(const size_t idx, bool is_first, bool print_args,
|
||||
size_t first_arg_idx) const
|
||||
{
|
||||
if (idx >= regs.size()) {
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
std::stringstream translator;
|
||||
|
||||
if (!is_first) {
|
||||
translator << ", ";
|
||||
} else {
|
||||
translator << " ";
|
||||
}
|
||||
|
||||
if (print_args && regs[idx] >= first_arg_idx) {
|
||||
translator << "a" << regs[idx] - first_arg_idx;
|
||||
} else {
|
||||
translator << "v" << regs[idx];
|
||||
}
|
||||
|
||||
return translator.str();
|
||||
}
|
||||
|
||||
std::string panda::pandasm::Ins::ImmToString(const size_t idx, bool is_first) const
|
||||
{
|
||||
if (idx >= imms.size()) {
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
auto *number = std::get_if<double>(&(imms[idx]));
|
||||
std::stringstream translator;
|
||||
|
||||
if (!is_first) {
|
||||
translator << ", ";
|
||||
} else {
|
||||
translator << " ";
|
||||
}
|
||||
|
||||
if (number != nullptr) {
|
||||
translator << std::scientific << *number;
|
||||
} else {
|
||||
translator << "0x" << std::hex << std::get<int64_t>(imms[idx]);
|
||||
}
|
||||
|
||||
return translator.str();
|
||||
}
|
||||
|
||||
std::string panda::pandasm::Ins::IdToString(const size_t idx, bool is_first) const
|
||||
{
|
||||
if (idx >= ids.size()) {
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
std::stringstream translator;
|
||||
|
||||
if (!is_first) {
|
||||
translator << ", ";
|
||||
} else {
|
||||
translator << " ";
|
||||
}
|
||||
|
||||
translator << ids[idx];
|
||||
|
||||
return translator.str();
|
||||
}
|
||||
} // namespace panda::pandasm
|
259
static_core/assembler/assembly-ins.h
Normal file
259
static_core/assembler/assembly-ins.h
Normal file
@ -0,0 +1,259 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_INS_HPP
|
||||
#define _PANDA_ASSEMBLER_INS_HPP
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "assembly-debug.h"
|
||||
#include "bytecode_emitter.h"
|
||||
#include "file_items.h"
|
||||
#include "isa.h"
|
||||
#include "lexer.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
enum class Opcode {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs, prof_size) opcode,
|
||||
PANDA_INSTRUCTION_LIST(OPLIST)
|
||||
#undef OPLIST
|
||||
INVALID,
|
||||
NUM_OPCODES = INVALID
|
||||
};
|
||||
|
||||
enum InstFlags {
|
||||
NONE = 0,
|
||||
JUMP = (1U << 0U),
|
||||
COND = (1U << 1U),
|
||||
CALL = (1U << 2U),
|
||||
RETURN = (1U << 3U),
|
||||
ACC_READ = (1U << 4U),
|
||||
ACC_WRITE = (1U << 5U),
|
||||
PSEUDO = (1U << 6U),
|
||||
THROWING = (1U << 7U),
|
||||
METHOD_ID = (1U << 8U),
|
||||
FIELD_ID = (1U << 9U),
|
||||
TYPE_ID = (1U << 10U),
|
||||
STRING_ID = (1U << 11U),
|
||||
LITERALARRAY_ID = (1U << 12U),
|
||||
CALL_RANGE = (1U << 13U)
|
||||
};
|
||||
|
||||
constexpr int INVALID_REG_IDX = -1;
|
||||
|
||||
constexpr size_t MAX_NUMBER_OF_SRC_REGS = 5; // TODO(mbolshov): auto-generate
|
||||
|
||||
constexpr InstFlags operator|(InstFlags a, InstFlags b)
|
||||
{
|
||||
using Utype = std::underlying_type_t<InstFlags>;
|
||||
return static_cast<InstFlags>(static_cast<Utype>(a) | static_cast<Utype>(b));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs, prof_size) flags,
|
||||
constexpr std::array<unsigned, static_cast<size_t>(Opcode::NUM_OPCODES)> INST_FLAGS_TABLE = {
|
||||
PANDA_INSTRUCTION_LIST(OPLIST)};
|
||||
#undef OPLIST
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs, prof_size) width,
|
||||
constexpr std::array<size_t, static_cast<size_t>(Opcode::NUM_OPCODES)> INST_WIDTH_TABLE = {
|
||||
PANDA_INSTRUCTION_LIST(OPLIST)};
|
||||
#undef OPLIST
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs, prof_size) def_idx,
|
||||
constexpr std::array<int, static_cast<size_t>(Opcode::NUM_OPCODES)> DEF_IDX_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)};
|
||||
#undef OPLIST
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs, prof_size) use_idxs,
|
||||
// clang-format off
|
||||
constexpr std::array<std::array<int, MAX_NUMBER_OF_SRC_REGS>, static_cast<size_t>(Opcode::NUM_OPCODES)> USE_IDXS_TABLE = {
|
||||
PANDA_INSTRUCTION_LIST(OPLIST)};
|
||||
// clang-format on
|
||||
#undef OPLIST
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs, prof_size) prof_size,
|
||||
constexpr std::array<unsigned, static_cast<size_t>(Opcode::NUM_OPCODES) + 1> INST_PROFILE_SIZES = {
|
||||
PANDA_INSTRUCTION_LIST(OPLIST) 0};
|
||||
#undef OPLIST
|
||||
|
||||
// NOLINTBEGIN(misc-non-private-member-variables-in-classes)
|
||||
struct Ins {
|
||||
using IType = std::variant<int64_t, double>;
|
||||
|
||||
constexpr static uint16_t ACCUMULATOR = -1;
|
||||
constexpr static size_t MAX_CALL_SHORT_ARGS = 2;
|
||||
constexpr static size_t MAX_CALL_ARGS = 4;
|
||||
constexpr static uint16_t MAX_NON_RANGE_CALL_REG = 15;
|
||||
constexpr static uint16_t MAX_RANGE_CALL_START_REG = 255;
|
||||
|
||||
Opcode opcode = Opcode::INVALID; /* operation type */
|
||||
std::vector<uint16_t> regs; /* list of arguments - registers */
|
||||
std::vector<std::string> ids; /* list of arguments - identifiers */
|
||||
std::vector<IType> imms; /* list of arguments - immediates */
|
||||
std::string label; /* label at the beginning of a line */
|
||||
bool set_label = false; /* whether this label is defined */
|
||||
debuginfo::Ins ins_debug;
|
||||
uint16_t profile_id {0}; /* Index in the profile vector */
|
||||
|
||||
PANDA_PUBLIC_API std::string ToString(const std::string &endline = "", bool print_args = false,
|
||||
size_t first_arg_idx = 0) const;
|
||||
|
||||
bool Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string_view, panda_file::StringItem *> &strings,
|
||||
const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays,
|
||||
const std::unordered_map<std::string_view, panda::Label> &labels) const;
|
||||
|
||||
size_t OperandListLength() const
|
||||
{
|
||||
return regs.size() + ids.size() + imms.size();
|
||||
}
|
||||
|
||||
bool HasFlag(InstFlags flag) const
|
||||
{
|
||||
if (opcode == Opcode::INVALID) { // TODO(mbolshov): introduce 'label' opcode for labels
|
||||
return false;
|
||||
}
|
||||
return (INST_FLAGS_TABLE[static_cast<size_t>(opcode)] & flag) != 0;
|
||||
}
|
||||
|
||||
bool CanThrow() const
|
||||
{
|
||||
return HasFlag(InstFlags::THROWING) || HasFlag(InstFlags::METHOD_ID) || HasFlag(InstFlags::FIELD_ID) ||
|
||||
HasFlag(InstFlags::TYPE_ID) || HasFlag(InstFlags::STRING_ID);
|
||||
}
|
||||
|
||||
bool IsJump() const
|
||||
{
|
||||
return HasFlag(InstFlags::JUMP);
|
||||
}
|
||||
|
||||
bool IsConditionalJump() const
|
||||
{
|
||||
return IsJump() && HasFlag(InstFlags::COND);
|
||||
}
|
||||
|
||||
bool IsCall() const
|
||||
{ // Non-range call
|
||||
return HasFlag(InstFlags::CALL);
|
||||
}
|
||||
|
||||
bool IsCallRange() const
|
||||
{ // Range call
|
||||
return HasFlag(InstFlags::CALL_RANGE);
|
||||
}
|
||||
|
||||
bool IsPseudoCall() const
|
||||
{
|
||||
return HasFlag(InstFlags::PSEUDO) && HasFlag(InstFlags::CALL);
|
||||
}
|
||||
|
||||
bool IsReturn() const
|
||||
{
|
||||
return HasFlag(InstFlags::RETURN);
|
||||
}
|
||||
|
||||
size_t MaxRegEncodingWidth() const
|
||||
{
|
||||
if (opcode == Opcode::INVALID) {
|
||||
return 0;
|
||||
}
|
||||
return INST_WIDTH_TABLE[static_cast<size_t>(opcode)];
|
||||
}
|
||||
|
||||
std::vector<uint16_t> Uses() const
|
||||
{
|
||||
if (IsPseudoCall()) {
|
||||
return regs;
|
||||
}
|
||||
|
||||
if (opcode == Opcode::INVALID) {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto use_idxs = USE_IDXS_TABLE[static_cast<size_t>(opcode)];
|
||||
std::vector<uint16_t> res(MAX_NUMBER_OF_SRC_REGS + 1);
|
||||
if (HasFlag(InstFlags::ACC_READ)) {
|
||||
res.push_back(Ins::ACCUMULATOR);
|
||||
}
|
||||
for (auto idx : use_idxs) {
|
||||
if (idx == INVALID_REG_IDX) {
|
||||
break;
|
||||
}
|
||||
ASSERT(static_cast<size_t>(idx) < regs.size());
|
||||
res.emplace_back(regs[idx]);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
std::optional<size_t> Def() const
|
||||
{
|
||||
if (opcode == Opcode::INVALID) {
|
||||
return {};
|
||||
}
|
||||
auto def_idx = DEF_IDX_TABLE[static_cast<size_t>(opcode)];
|
||||
if (def_idx != INVALID_REG_IDX) {
|
||||
return regs[def_idx];
|
||||
}
|
||||
if (HasFlag(InstFlags::ACC_WRITE)) {
|
||||
return Ins::ACCUMULATOR;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool IsValidToEmit() const
|
||||
{
|
||||
const auto invalid_reg_num = 1U << MaxRegEncodingWidth();
|
||||
for (auto reg : regs) {
|
||||
if (reg >= invalid_reg_num) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasDebugInfo() const
|
||||
{
|
||||
return ins_debug.line_number != 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string OperandsToString(bool print_args = false, size_t first_arg_idx = 0) const;
|
||||
std::string RegsToString(bool &first, bool print_args = false, size_t first_arg_idx = 0) const;
|
||||
std::string ImmsToString(bool &first) const;
|
||||
std::string IdsToString(bool &first) const;
|
||||
|
||||
std::string IdToString(size_t idx, bool is_first) const;
|
||||
std::string ImmToString(size_t idx, bool is_first) const;
|
||||
std::string RegToString(size_t idx, bool is_first, bool print_args = false, size_t first_arg_idx = 0) const;
|
||||
};
|
||||
// NOLINTEND(misc-non-private-member-variables-in-classes)
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_INS_HPP
|
38
static_core/assembler/assembly-label.h
Normal file
38
static_core/assembler/assembly-label.h
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_LABEL_HPP
|
||||
#define _PANDA_ASSEMBLER_LABEL_HPP
|
||||
|
||||
#include <string>
|
||||
#include "assembly-file-location.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
struct Label {
|
||||
std::string name; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
std::optional<FileLocation> file_location; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
|
||||
Label(std::string s, size_t b_l, size_t b_r, std::string f_c, bool d, size_t l_n)
|
||||
: name(std::move(s)), file_location({f_c, b_l, b_r, l_n, d})
|
||||
{
|
||||
}
|
||||
|
||||
explicit Label(std::string s) : name(std::move(s)) {}
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_LABEL_HPP
|
244
static_core/assembler/assembly-literals.h
Normal file
244
static_core/assembler/assembly-literals.h
Normal file
@ -0,0 +1,244 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_LITERALARRAY_HPP
|
||||
#define _PANDA_ASSEMBLER_LITERALARRAY_HPP
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "libpandafile/literal_data_accessor-inl.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
struct LiteralArray {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
struct Literal {
|
||||
// NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
|
||||
panda_file::LiteralTag tag;
|
||||
// NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
|
||||
std::variant<bool, uint8_t, uint16_t, uint32_t, uint64_t, float, double, std::string> value;
|
||||
|
||||
bool IsSigned() const
|
||||
{
|
||||
switch (tag) {
|
||||
case panda_file::LiteralTag::ARRAY_I8:
|
||||
case panda_file::LiteralTag::ARRAY_I16:
|
||||
case panda_file::LiteralTag::ARRAY_I32:
|
||||
case panda_file::LiteralTag::ARRAY_I64:
|
||||
case panda_file::LiteralTag::INTEGER:
|
||||
case panda_file::LiteralTag::BIGINT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsArray() const
|
||||
{
|
||||
switch (tag) {
|
||||
case panda_file::LiteralTag::ARRAY_U1:
|
||||
case panda_file::LiteralTag::ARRAY_U8:
|
||||
case panda_file::LiteralTag::ARRAY_I8:
|
||||
case panda_file::LiteralTag::ARRAY_U16:
|
||||
case panda_file::LiteralTag::ARRAY_I16:
|
||||
case panda_file::LiteralTag::ARRAY_U32:
|
||||
case panda_file::LiteralTag::ARRAY_I32:
|
||||
case panda_file::LiteralTag::ARRAY_U64:
|
||||
case panda_file::LiteralTag::ARRAY_I64:
|
||||
case panda_file::LiteralTag::ARRAY_F32:
|
||||
case panda_file::LiteralTag::ARRAY_F64:
|
||||
case panda_file::LiteralTag::ARRAY_STRING:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsBoolValue() const
|
||||
{
|
||||
switch (tag) {
|
||||
case panda_file::LiteralTag::ARRAY_U1:
|
||||
case panda_file::LiteralTag::BOOL:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsByteValue() const
|
||||
{
|
||||
switch (tag) {
|
||||
case panda_file::LiteralTag::ARRAY_U8:
|
||||
case panda_file::LiteralTag::ARRAY_I8:
|
||||
case panda_file::LiteralTag::TAGVALUE:
|
||||
case panda_file::LiteralTag::ACCESSOR:
|
||||
case panda_file::LiteralTag::NULLVALUE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsShortValue() const
|
||||
{
|
||||
switch (tag) {
|
||||
case panda_file::LiteralTag::ARRAY_U16:
|
||||
case panda_file::LiteralTag::ARRAY_I16:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsIntegerValue() const
|
||||
{
|
||||
switch (tag) {
|
||||
case panda_file::LiteralTag::ARRAY_U32:
|
||||
case panda_file::LiteralTag::ARRAY_I32:
|
||||
case panda_file::LiteralTag::INTEGER:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsLongValue() const
|
||||
{
|
||||
switch (tag) {
|
||||
case panda_file::LiteralTag::ARRAY_U64:
|
||||
case panda_file::LiteralTag::ARRAY_I64:
|
||||
case panda_file::LiteralTag::BIGINT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsFloatValue() const
|
||||
{
|
||||
switch (tag) {
|
||||
case panda_file::LiteralTag::ARRAY_F32:
|
||||
case panda_file::LiteralTag::FLOAT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsDoubleValue() const
|
||||
{
|
||||
switch (tag) {
|
||||
case panda_file::LiteralTag::ARRAY_F64:
|
||||
case panda_file::LiteralTag::DOUBLE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsStringValue() const
|
||||
{
|
||||
switch (tag) {
|
||||
case panda_file::LiteralTag::ARRAY_STRING:
|
||||
case panda_file::LiteralTag::STRING:
|
||||
case panda_file::LiteralTag::METHOD:
|
||||
case panda_file::LiteralTag::GENERATORMETHOD:
|
||||
case panda_file::LiteralTag::ASYNCGENERATORMETHOD:
|
||||
case panda_file::LiteralTag::ASYNCMETHOD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const LiteralArray::Literal &literal)
|
||||
{
|
||||
return tag == literal.tag && value == literal.value;
|
||||
}
|
||||
|
||||
bool operator!=(const LiteralArray::Literal &literal)
|
||||
{
|
||||
return !(*this == literal);
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<panda::pandasm::LiteralArray::Literal>
|
||||
literals; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
|
||||
explicit LiteralArray(std::vector<panda::pandasm::LiteralArray::Literal> literals_vec)
|
||||
: literals(std::move(literals_vec))
|
||||
{
|
||||
}
|
||||
explicit LiteralArray() = default;
|
||||
|
||||
static constexpr panda_file::LiteralTag GetArrayTagFromComponentType(panda_file::Type::TypeId type)
|
||||
{
|
||||
switch (type) {
|
||||
case panda_file::Type::TypeId::U1:
|
||||
return panda_file::LiteralTag::ARRAY_U1;
|
||||
case panda_file::Type::TypeId::U8:
|
||||
return panda_file::LiteralTag::ARRAY_U8;
|
||||
case panda_file::Type::TypeId::I8:
|
||||
return panda_file::LiteralTag::ARRAY_I8;
|
||||
case panda_file::Type::TypeId::U16:
|
||||
return panda_file::LiteralTag::ARRAY_U16;
|
||||
case panda_file::Type::TypeId::I16:
|
||||
return panda_file::LiteralTag::ARRAY_I16;
|
||||
case panda_file::Type::TypeId::U32:
|
||||
return panda_file::LiteralTag::ARRAY_U32;
|
||||
case panda_file::Type::TypeId::I32:
|
||||
return panda_file::LiteralTag::ARRAY_I32;
|
||||
case panda_file::Type::TypeId::U64:
|
||||
return panda_file::LiteralTag::ARRAY_U64;
|
||||
case panda_file::Type::TypeId::I64:
|
||||
return panda_file::LiteralTag::ARRAY_I64;
|
||||
case panda_file::Type::TypeId::F32:
|
||||
return panda_file::LiteralTag::ARRAY_F32;
|
||||
case panda_file::Type::TypeId::F64:
|
||||
return panda_file::LiteralTag::ARRAY_F64;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr panda_file::LiteralTag GetLiteralTagFromComponentType(panda_file::Type::TypeId type)
|
||||
{
|
||||
switch (type) {
|
||||
case panda_file::Type::TypeId::U1:
|
||||
return panda_file::LiteralTag::BOOL;
|
||||
case panda_file::Type::TypeId::U8:
|
||||
case panda_file::Type::TypeId::I8:
|
||||
case panda_file::Type::TypeId::U16:
|
||||
case panda_file::Type::TypeId::I16:
|
||||
case panda_file::Type::TypeId::U32:
|
||||
case panda_file::Type::TypeId::I32:
|
||||
return panda_file::LiteralTag::INTEGER;
|
||||
case panda_file::Type::TypeId::U64:
|
||||
case panda_file::Type::TypeId::I64:
|
||||
return panda_file::LiteralTag::BIGINT;
|
||||
case panda_file::Type::TypeId::F32:
|
||||
return panda_file::LiteralTag::FLOAT;
|
||||
case panda_file::Type::TypeId::F64:
|
||||
return panda_file::LiteralTag::DOUBLE;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_LITERALARRAY_HPP
|
31
static_core/assembler/assembly-methodhandle.h
Normal file
31
static_core/assembler/assembly-methodhandle.h
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_METHODHANDLE
|
||||
#define _PANDA_ASSEMBLER_METHODHANDLE
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
struct MethodHandle {
|
||||
std::string item_name; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
panda::panda_file::MethodHandleType type; // NOLINT(misc-non-private-member-variables-in-classes)
|
||||
MethodHandle(std::string s, panda::panda_file::MethodHandleType t) : item_name(std::move(s)), type(t) {}
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // _PANDA_ASSEMBLER_METHODHANDLE
|
2641
static_core/assembler/assembly-parser.cpp
Normal file
2641
static_core/assembler/assembly-parser.cpp
Normal file
File diff suppressed because it is too large
Load Diff
280
static_core/assembler/assembly-parser.h
Normal file
280
static_core/assembler/assembly-parser.h
Normal file
@ -0,0 +1,280 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_PARSER_HPP
|
||||
#define _PANDA_ASSEMBLER_PARSER_HPP
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "assembly-context.h"
|
||||
#include "assembly-emitter.h"
|
||||
#include "assembly-field.h"
|
||||
#include "assembly-function.h"
|
||||
#include "assembly-ins.h"
|
||||
#include "assembly-label.h"
|
||||
#include "assembly-program.h"
|
||||
#include "assembly-record.h"
|
||||
#include "assembly-type.h"
|
||||
#include "define.h"
|
||||
#include "error.h"
|
||||
#include "ide_helpers.h"
|
||||
#include "lexer.h"
|
||||
#include "meta.h"
|
||||
#include "utils/expected.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
using Instructions = std::pair<std::vector<Ins>, Error>;
|
||||
|
||||
using Functions = std::pair<std::unordered_map<std::string, Function>, std::unordered_map<std::string, Record>>;
|
||||
|
||||
class Parser {
|
||||
public:
|
||||
Parser() = default;
|
||||
|
||||
NO_MOVE_SEMANTIC(Parser);
|
||||
NO_COPY_SEMANTIC(Parser);
|
||||
|
||||
~Parser() = default;
|
||||
|
||||
/*
|
||||
* The main function of parsing, which takes a vector of token vectors and a name of the source file.
|
||||
* Returns a program or an error value: Expected<Program, Error>
|
||||
* This function analyzes code containing several functions:
|
||||
* - Each function used must be declared.
|
||||
* - The correct function declaration looks like this: .function ret_type fun_name([param_type aN,]) [<metadata>]
|
||||
* ([data] shows that this 'data' is optional).
|
||||
* - N in function parameters must increase when number of parameters increases
|
||||
* (Possible: a0, a1,..., aN. Impossible: a1, a10, a13).
|
||||
* - Each function has its own label table.
|
||||
*/
|
||||
PANDA_PUBLIC_API Expected<Program, Error> Parse(TokenSet &vectors_tokens, const std::string &file_name = "");
|
||||
|
||||
/*
|
||||
* The main function of parsing, which takes a string with source and a name of the source file.
|
||||
* Returns a program or an error value: Expected<Program, Error>
|
||||
*/
|
||||
PANDA_PUBLIC_API Expected<Program, Error> Parse(const std::string &source, const std::string &file_name = "");
|
||||
|
||||
/*
|
||||
* Returns a set error
|
||||
*/
|
||||
Error ShowError() const
|
||||
{
|
||||
return err_;
|
||||
}
|
||||
|
||||
ErrorList ShowWarnings() const
|
||||
{
|
||||
return war_;
|
||||
}
|
||||
|
||||
private:
|
||||
panda::pandasm::Program program_;
|
||||
std::unordered_map<std::string, panda::pandasm::Label> *label_table_ = nullptr;
|
||||
Metadata *metadata_ = nullptr;
|
||||
Context context_; /* token iterator */
|
||||
panda::pandasm::Record *curr_record_ = nullptr;
|
||||
panda::pandasm::LiteralArray *curr_array_ = nullptr;
|
||||
bool is_const_array_ = false;
|
||||
panda::pandasm::LiteralArray::Literal *curr_array_elem_ = nullptr;
|
||||
panda::pandasm::Function *curr_func_ = nullptr;
|
||||
panda::pandasm::Ins *curr_ins_ = nullptr;
|
||||
panda::pandasm::Field *curr_fld_ = nullptr;
|
||||
size_t line_stric_ = 0;
|
||||
panda::pandasm::Error err_;
|
||||
panda::pandasm::ErrorList war_;
|
||||
bool open_ = false; /* flag of being in a code section */
|
||||
bool record_def_ = false;
|
||||
bool array_def_ = false;
|
||||
bool func_def_ = false;
|
||||
static constexpr uint32_t INTRO_CONST_ARRAY_LITERALS_NUMBER = 2;
|
||||
|
||||
inline Error GetError(const std::string &mess = "", Error::ErrorType err = Error::ErrorType::ERR_NONE,
|
||||
int8_t shift = 0, int token_shift = 0, const std::string &add_mess = "") const
|
||||
{
|
||||
return Error(mess, line_stric_, err, add_mess,
|
||||
context_.tokens[static_cast<int>(context_.number) + token_shift - 1].bound_left + shift,
|
||||
context_.tokens[static_cast<int>(context_.number) + token_shift - 1].bound_right,
|
||||
context_.tokens[static_cast<int>(context_.number) + token_shift - 1].whole_line);
|
||||
}
|
||||
|
||||
inline void GetWarning(const std::string &mess = "", Error::ErrorType err = Error::ErrorType::ERR_NONE,
|
||||
int8_t shift = 0, const std::string &add_mess = "")
|
||||
{
|
||||
war_.emplace_back(mess, line_stric_, err, add_mess,
|
||||
context_.tokens[context_.number - 1].bound_left + static_cast<size_t>(shift),
|
||||
context_.tokens[context_.number - 1].bound_right,
|
||||
context_.tokens[context_.number - 1].whole_line, Error::ErrorClass::WARNING);
|
||||
}
|
||||
|
||||
SourcePosition GetCurrentPosition(bool left_bound) const
|
||||
{
|
||||
if (left_bound) {
|
||||
return SourcePosition {line_stric_, context_.tokens[context_.number - 1].bound_left};
|
||||
}
|
||||
return SourcePosition {line_stric_, context_.tokens[context_.number - 1].bound_right};
|
||||
}
|
||||
|
||||
bool LabelValidName();
|
||||
bool TypeValidName();
|
||||
bool RegValidName();
|
||||
bool ParamValidName();
|
||||
bool FunctionValidName();
|
||||
bool ParseFunctionName();
|
||||
bool ParseLabel();
|
||||
bool ParseOperation();
|
||||
bool ParseOperands();
|
||||
bool ParseFunctionCode();
|
||||
bool ParseFunctionInstruction();
|
||||
bool ParseFunctionFullSign();
|
||||
bool UpdateFunctionName();
|
||||
bool ParseFunctionReturn();
|
||||
bool ParseFunctionArg();
|
||||
bool ParseFunctionArgComma(bool &comma);
|
||||
bool ParseFunctionArgs();
|
||||
bool ParseType(Type *type);
|
||||
bool PrefixedValidName(bool allow_brackets = false);
|
||||
bool ParseMetaListComma(bool &comma, bool eq);
|
||||
bool MeetExpMetaList(bool eq);
|
||||
bool BuildMetaListAttr(bool &eq, std::string &attribute_name, std::string &attribute_value);
|
||||
bool ParseMetaList(bool flag);
|
||||
bool ParseMetaDef();
|
||||
bool ParseRecordFullSign();
|
||||
bool ParseRecordFields();
|
||||
bool ParseRecordField();
|
||||
bool ParseRecordName();
|
||||
bool RecordValidName();
|
||||
bool ParseArrayFullSign();
|
||||
bool IsConstArray();
|
||||
bool ParseArrayName();
|
||||
bool ArrayValidName();
|
||||
bool ArrayElementsValidNumber();
|
||||
bool ParseArrayElements();
|
||||
bool ParseArrayElement();
|
||||
bool ParseArrayElementType();
|
||||
bool ParseArrayElementValue();
|
||||
bool ParseArrayElementValueInteger();
|
||||
bool ParseArrayElementValueFloat();
|
||||
bool ParseArrayElementValueString();
|
||||
bool ParseFieldName();
|
||||
bool ParseFieldType();
|
||||
std::optional<std::string> ParseStringLiteral();
|
||||
int64_t MnemonicToBuiltinId();
|
||||
uint8_t ParseMultiArrayHallmark();
|
||||
|
||||
bool ParseInteger(int64_t *value);
|
||||
bool ParseFloat(double *value, bool is_64bit);
|
||||
bool ParseOperandVreg();
|
||||
bool ParseOperandComma();
|
||||
bool ParseOperandInteger();
|
||||
bool ParseOperandFloat(bool is_64bit);
|
||||
bool ParseOperandId();
|
||||
bool ParseOperandLabel();
|
||||
bool ParseOperandField();
|
||||
bool ParseOperandType(Type::VerificationType ver_type);
|
||||
bool ParseOperandNone();
|
||||
bool ParseOperandString();
|
||||
bool ParseOperandLiteralArray();
|
||||
bool ParseOperandCall();
|
||||
bool ParseOperandSignature(std::string *sign);
|
||||
bool ParseOperandSignatureTypesList(std::string *sign);
|
||||
bool ParseOperandBuiltinMnemonic();
|
||||
bool ParseOperandInitobj();
|
||||
|
||||
void SetFunctionInformation();
|
||||
void SetRecordInformation(const std::string &record_name);
|
||||
void SetArrayInformation();
|
||||
void SetOperationInformation();
|
||||
void ParseAsCatchall(const std::vector<Token> &tokens);
|
||||
void ParseAsLanguage(const std::vector<Token> &tokens, bool &is_lang_parsed, bool &is_first_statement);
|
||||
void ParseAsRecord(const std::vector<Token> &tokens);
|
||||
void ParseAsArray(const std::vector<Token> &tokens);
|
||||
void ParseAsFunction(const std::vector<Token> &tokens);
|
||||
void ParseAsUnionField(const std::vector<Token> &tokens);
|
||||
void ParseAsBraceRight(const std::vector<Token> &tokens);
|
||||
bool ParseAfterLine(bool &is_first_statement);
|
||||
Expected<Program, Error> ParseAfterMainLoop(const std::string &file_name);
|
||||
void ParseResetFunctionLabelsAndParams();
|
||||
void ParseResetTables();
|
||||
void ParseResetFunctionTable();
|
||||
void ParseResetRecordTable();
|
||||
void ParseResetArrayTable();
|
||||
void ParseAsLanguageDirective();
|
||||
Function::CatchBlock PrepareCatchBlock(bool is_catchall, size_t size, size_t catchall_tokens_num,
|
||||
size_t catch_tokens_num);
|
||||
void ParseAsCatchDirective();
|
||||
void SetError();
|
||||
void SetMetadataContextError(const Metadata::Error &err, bool has_value);
|
||||
|
||||
Expected<char, Error> ParseOctalEscapeSequence(std::string_view s, size_t *i);
|
||||
Expected<char, Error> ParseHexEscapeSequence(std::string_view s, size_t *i);
|
||||
Expected<char, Error> ParseEscapeSequence(std::string_view s, size_t *i);
|
||||
|
||||
template <class T>
|
||||
auto TryEmplaceInTable(bool flag, T &item, const std::string &cid)
|
||||
{
|
||||
return item.try_emplace(cid, cid, program_.lang, context_.tokens[context_.number - 1].bound_left,
|
||||
context_.tokens[context_.number - 1].bound_right,
|
||||
context_.tokens[context_.number - 1].whole_line, flag, line_stric_);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool AddObjectInTable(bool flag, T &item, const std::string &cid = "")
|
||||
{
|
||||
std::string elem = !cid.empty() ? cid : std::string(context_.GiveToken().data(), context_.GiveToken().length());
|
||||
auto [iter, is_inserted] = TryEmplaceInTable(flag, item, elem);
|
||||
|
||||
if (is_inserted) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (iter->second.file_location->is_defined && flag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!iter->second.file_location->is_defined && flag) {
|
||||
iter->second.file_location->is_defined = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!iter->second.file_location->is_defined) {
|
||||
iter->second.file_location->bound_left = context_.tokens[context_.number - 1].bound_left;
|
||||
iter->second.file_location->bound_right = context_.tokens[context_.number - 1].bound_right;
|
||||
iter->second.file_location->whole_line = context_.tokens[context_.number - 1].whole_line;
|
||||
iter->second.file_location->line_number = line_stric_;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
inline auto Parser::TryEmplaceInTable(bool flag, std::unordered_map<std::string, panda::pandasm::Label> &item,
|
||||
[[maybe_unused]] const std::string &cid)
|
||||
{
|
||||
return item.try_emplace(std::string(context_.GiveToken().data(), context_.GiveToken().length()),
|
||||
std::string(context_.GiveToken().data(), context_.GiveToken().length()),
|
||||
context_.tokens[context_.number - 1].bound_left,
|
||||
context_.tokens[context_.number - 1].bound_right,
|
||||
context_.tokens[context_.number - 1].whole_line, flag, line_stric_);
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_PARSER_HPP
|
34
static_core/assembler/assembly-program.cpp
Normal file
34
static_core/assembler/assembly-program.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "assembly-program.h"
|
||||
#include "ide_helpers.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
std::string Program::JsonDump() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "{ \"functions\": ";
|
||||
ss << JsonSerializeProgramItems(function_table);
|
||||
ss << ", \"records\": ";
|
||||
ss << JsonSerializeProgramItems(record_table);
|
||||
ss << " }";
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
51
static_core/assembler/assembly-program.h
Normal file
51
static_core/assembler/assembly-program.h
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_PROGRAM_HPP
|
||||
#define _PANDA_ASSEMBLER_PROGRAM_HPP
|
||||
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "assembly-function.h"
|
||||
#include "assembly-record.h"
|
||||
#include "assembly-type.h"
|
||||
#include "assembly-methodhandle.h"
|
||||
#include "assembly-literals.h"
|
||||
#include "extensions/extensions.h"
|
||||
#include "macros.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
// NOLINTBEGIN(misc-non-private-member-variables-in-classes)
|
||||
struct Program {
|
||||
panda::panda_file::SourceLang lang {panda::panda_file::SourceLang::PANDA_ASSEMBLY};
|
||||
std::unordered_map<std::string, panda::pandasm::Record> record_table;
|
||||
std::unordered_map<std::string, panda::pandasm::Function> function_table;
|
||||
std::unordered_map<std::string, std::vector<std::string>> function_synonyms;
|
||||
std::map<std::string, panda::pandasm::LiteralArray> literalarray_table;
|
||||
std::unordered_set<std::string> strings;
|
||||
std::unordered_set<Type> array_types;
|
||||
|
||||
/*
|
||||
* Returns a JSON string with the program structure and scopes locations
|
||||
*/
|
||||
PANDA_PUBLIC_API std::string JsonDump() const;
|
||||
};
|
||||
// NOLINTEND(misc-non-private-member-variables-in-classes)
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_PROGRAM_HPP
|
66
static_core/assembler/assembly-record.h
Normal file
66
static_core/assembler/assembly-record.h
Normal file
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_RECORD_HPP
|
||||
#define _PANDA_ASSEMBLER_RECORD_HPP
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "assembly-field.h"
|
||||
#include "extensions/extensions.h"
|
||||
#include "ide_helpers.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
// NOLINTBEGIN(misc-non-private-member-variables-in-classes)
|
||||
struct Record {
|
||||
std::string name;
|
||||
bool conflict = false; /* Name is conflict with panda primitive types. Need special handle. */
|
||||
panda::panda_file::SourceLang language;
|
||||
std::unique_ptr<RecordMetadata> metadata;
|
||||
std::vector<Field> field_list; /* class fields list */
|
||||
size_t params_num = 0;
|
||||
bool body_presence = false;
|
||||
SourceLocation body_location;
|
||||
std::string source_file; /* The file in which the record is defined or empty */
|
||||
std::optional<FileLocation> file_location;
|
||||
|
||||
Record(std::string s, panda::panda_file::SourceLang lang, size_t b_l, size_t b_r, std::string f_c, bool d,
|
||||
size_t l_n)
|
||||
: name(std::move(s)),
|
||||
language(lang),
|
||||
metadata(extensions::MetadataExtension::CreateRecordMetadata(lang)),
|
||||
file_location({f_c, b_l, b_r, l_n, d})
|
||||
{
|
||||
}
|
||||
|
||||
Record(std::string s, panda::panda_file::SourceLang lang)
|
||||
: name(std::move(s)), language(lang), metadata(extensions::MetadataExtension::CreateRecordMetadata(lang))
|
||||
{
|
||||
}
|
||||
|
||||
bool HasImplementation() const
|
||||
{
|
||||
return !metadata->IsForeign();
|
||||
}
|
||||
};
|
||||
// NOLINTEND(misc-non-private-member-variables-in-classes)
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_RECORD_HPP
|
132
static_core/assembler/assembly-type.cpp
Normal file
132
static_core/assembler/assembly-type.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "assembly-type.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
// NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
|
||||
static std::unordered_map<std::string_view, std::string_view> PRIMITIVE_TYPES = {
|
||||
{"u1", "Z"}, {"i8", "B"}, {"u8", "H"}, {"i16", "S"}, {"u16", "C"}, {"i32", "I"}, {"u32", "U"},
|
||||
{"f32", "F"}, {"f64", "D"}, {"i64", "J"}, {"u64", "Q"}, {"void", "V"}, {"any", "A"}};
|
||||
|
||||
std::string Type::GetDescriptor(bool ignore_primitive) const
|
||||
{
|
||||
if (!ignore_primitive) {
|
||||
auto it = PRIMITIVE_TYPES.find(component_name_);
|
||||
if (it != PRIMITIVE_TYPES.cend()) {
|
||||
return std::string(rank_, '[') + it->second.data();
|
||||
}
|
||||
}
|
||||
|
||||
std::string res = std::string(rank_, '[') + "L" + component_name_ + ";";
|
||||
std::replace(res.begin(), res.end(), '.', '/');
|
||||
return res;
|
||||
}
|
||||
|
||||
/* static */
|
||||
panda_file::Type::TypeId Type::GetId(std::string_view name, bool ignore_primitive)
|
||||
{
|
||||
static std::unordered_map<std::string_view, panda_file::Type::TypeId> panda_types = {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define PANDATYPE(name, inst_code) {std::string_view(name), panda_file::Type::TypeId::inst_code},
|
||||
PANDA_ASSEMBLER_TYPES(PANDATYPE)
|
||||
#undef PANDATYPE
|
||||
};
|
||||
|
||||
if (!ignore_primitive) {
|
||||
auto iter = panda_types.find(name);
|
||||
|
||||
if (iter == panda_types.end()) {
|
||||
return panda_file::Type::TypeId::REFERENCE;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
return panda_file::Type::TypeId::REFERENCE;
|
||||
}
|
||||
|
||||
/* static */
|
||||
std::string Type::GetName(std::string_view component_name, size_t rank)
|
||||
{
|
||||
std::string name(component_name);
|
||||
while (rank-- > 0) {
|
||||
name += "[]";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/* static */
|
||||
Type Type::FromDescriptor(std::string_view descriptor)
|
||||
{
|
||||
static std::unordered_map<std::string_view, std::string_view> reverse_primitive_types = {
|
||||
{"Z", "u1"}, {"B", "i8"}, {"H", "u8"}, {"S", "i16"}, {"C", "u16"}, {"I", "i32"}, {"U", "u32"},
|
||||
{"F", "f32"}, {"D", "f64"}, {"J", "i64"}, {"Q", "u64"}, {"V", "void"}, {"A", "any"}};
|
||||
|
||||
size_t i = 0;
|
||||
while (descriptor[i] == '[') {
|
||||
++i;
|
||||
}
|
||||
|
||||
size_t rank = i;
|
||||
bool is_ref_type = descriptor[i] == 'L';
|
||||
if (is_ref_type) {
|
||||
descriptor.remove_suffix(1); /* Remove semicolon */
|
||||
++i;
|
||||
}
|
||||
|
||||
descriptor.remove_prefix(i);
|
||||
|
||||
if (is_ref_type) {
|
||||
return Type(descriptor, rank);
|
||||
}
|
||||
|
||||
return Type(reverse_primitive_types[descriptor], rank);
|
||||
}
|
||||
|
||||
/* static */
|
||||
Type Type::FromName(std::string_view name, bool ignore_primitive)
|
||||
{
|
||||
constexpr size_t STEP = 2;
|
||||
|
||||
size_t size = name.size();
|
||||
size_t i = 0;
|
||||
|
||||
while (name[size - i - 1] == ']') {
|
||||
i += STEP;
|
||||
}
|
||||
|
||||
name.remove_suffix(i);
|
||||
|
||||
return Type(name, i / STEP, ignore_primitive);
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool Type::IsStringType(const std::string &name, panda::panda_file::SourceLang lang)
|
||||
{
|
||||
auto string_type = Type::FromDescriptor(panda::panda_file::GetStringClassDescriptor(lang));
|
||||
return name == string_type.GetName();
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool Type::IsPandaPrimitiveType(const std::string &name)
|
||||
{
|
||||
auto it = PRIMITIVE_TYPES.find(name);
|
||||
return it != PRIMITIVE_TYPES.cend();
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
197
static_core/assembler/assembly-type.h
Normal file
197
static_core/assembler/assembly-type.h
Normal file
@ -0,0 +1,197 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_TYPE_H
|
||||
#define _PANDA_ASSEMBLER_TYPE_H
|
||||
|
||||
#include "define.h"
|
||||
#include "file_items.h"
|
||||
#include "isa.h"
|
||||
#include "libpandabase/macros.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
class Type {
|
||||
public:
|
||||
enum VerificationType {
|
||||
TYPE_ID_OBJECT,
|
||||
TYPE_ID_ARRAY,
|
||||
TYPE_ID_CLASS,
|
||||
TYPE_ID_ANY_OBJECT,
|
||||
};
|
||||
|
||||
Type() = default;
|
||||
DEFAULT_MOVE_SEMANTIC(Type);
|
||||
DEFAULT_COPY_SEMANTIC(Type);
|
||||
~Type() = default;
|
||||
|
||||
Type(std::string_view component_name, size_t rank, bool ignore_primitive = false)
|
||||
: component_name_(component_name), rank_(rank)
|
||||
{
|
||||
name_ = GetName(component_name_, rank_);
|
||||
type_id_ = GetId(name_, ignore_primitive);
|
||||
}
|
||||
|
||||
Type(const Type &component_type, size_t rank)
|
||||
: Type(component_type.GetComponentName(), component_type.GetRank() + rank)
|
||||
{
|
||||
}
|
||||
|
||||
PANDA_PUBLIC_API std::string GetDescriptor(bool ignore_primitive = false) const;
|
||||
|
||||
PANDA_PUBLIC_API std::string GetName() const
|
||||
{
|
||||
return name_;
|
||||
}
|
||||
|
||||
std::string GetPandasmName() const
|
||||
{
|
||||
std::string name_pa {name_};
|
||||
std::replace(name_pa.begin(), name_pa.end(), '/', '.');
|
||||
return name_pa;
|
||||
}
|
||||
|
||||
std::string GetComponentName() const
|
||||
{
|
||||
return component_name_;
|
||||
}
|
||||
|
||||
size_t GetRank() const
|
||||
{
|
||||
return rank_;
|
||||
}
|
||||
|
||||
Type GetComponentType() const
|
||||
{
|
||||
return Type(component_name_, rank_ > 0 ? rank_ - 1 : 0);
|
||||
}
|
||||
|
||||
panda_file::Type::TypeId GetId() const
|
||||
{
|
||||
return type_id_;
|
||||
}
|
||||
|
||||
bool IsArrayContainsPrimTypes() const
|
||||
{
|
||||
auto elem = GetId(component_name_);
|
||||
return elem != panda_file::Type::TypeId::REFERENCE;
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return !component_name_.empty();
|
||||
}
|
||||
|
||||
bool IsArray() const
|
||||
{
|
||||
return rank_ > 0;
|
||||
}
|
||||
|
||||
bool IsObject() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::REFERENCE;
|
||||
}
|
||||
|
||||
bool IsTagged() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::TAGGED;
|
||||
}
|
||||
|
||||
bool IsIntegral() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::U1 || type_id_ == panda_file::Type::TypeId::U8 ||
|
||||
type_id_ == panda_file::Type::TypeId::I8 || type_id_ == panda_file::Type::TypeId::U16 ||
|
||||
type_id_ == panda_file::Type::TypeId::I16 || type_id_ == panda_file::Type::TypeId::U32 ||
|
||||
type_id_ == panda_file::Type::TypeId::I32 || type_id_ == panda_file::Type::TypeId::U64 ||
|
||||
type_id_ == panda_file::Type::TypeId::I64;
|
||||
}
|
||||
|
||||
bool FitsInto32() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::U1 || type_id_ == panda_file::Type::TypeId::U8 ||
|
||||
type_id_ == panda_file::Type::TypeId::I8 || type_id_ == panda_file::Type::TypeId::U16 ||
|
||||
type_id_ == panda_file::Type::TypeId::I16 || type_id_ == panda_file::Type::TypeId::U32 ||
|
||||
type_id_ == panda_file::Type::TypeId::I32;
|
||||
}
|
||||
|
||||
bool IsFloat32() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::F32;
|
||||
}
|
||||
|
||||
bool IsFloat64() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::F64;
|
||||
}
|
||||
|
||||
bool IsPrim32() const
|
||||
{
|
||||
return (IsIntegral() && FitsInto32()) || IsFloat32();
|
||||
}
|
||||
|
||||
bool IsPrim64() const
|
||||
{
|
||||
return (IsIntegral() && !FitsInto32()) || IsFloat64();
|
||||
}
|
||||
|
||||
bool IsPrimitive() const
|
||||
{
|
||||
return IsPrim64() || IsPrim32();
|
||||
}
|
||||
|
||||
bool IsVoid() const
|
||||
{
|
||||
return type_id_ == panda_file::Type::TypeId::VOID;
|
||||
}
|
||||
|
||||
PANDA_PUBLIC_API static panda_file::Type::TypeId GetId(std::string_view name, bool ignore_primitive = false);
|
||||
|
||||
bool operator==(const Type &type) const
|
||||
{
|
||||
return name_ == type.name_;
|
||||
}
|
||||
|
||||
static PANDA_PUBLIC_API Type FromDescriptor(std::string_view descriptor);
|
||||
|
||||
static PANDA_PUBLIC_API Type FromName(std::string_view name, bool ignore_primitive = false);
|
||||
|
||||
static PANDA_PUBLIC_API bool IsPandaPrimitiveType(const std::string &name);
|
||||
static bool IsStringType(const std::string &name, panda::panda_file::SourceLang lang);
|
||||
|
||||
private:
|
||||
static PANDA_PUBLIC_API std::string GetName(std::string_view component_name, size_t rank);
|
||||
|
||||
std::string component_name_;
|
||||
size_t rank_ {0};
|
||||
std::string name_;
|
||||
panda_file::Type::TypeId type_id_ {panda_file::Type::TypeId::VOID};
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
namespace std {
|
||||
|
||||
template <>
|
||||
class hash<panda::pandasm::Type> {
|
||||
public:
|
||||
size_t operator()(const panda::pandasm::Type &type) const
|
||||
{
|
||||
return std::hash<std::string>()(type.GetName());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_TYPE_H
|
210
static_core/assembler/context.cpp
Normal file
210
static_core/assembler/context.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <string_view>
|
||||
#include "assembly-parser.h"
|
||||
#include "utils/number-utils.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
void Context::Make(const std::vector<panda::pandasm::Token> &t)
|
||||
{
|
||||
err = {};
|
||||
|
||||
ins_number = 0;
|
||||
|
||||
tokens = t;
|
||||
|
||||
number = 1;
|
||||
|
||||
end = false;
|
||||
|
||||
token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left),
|
||||
tokens[number - 1].bound_right - tokens[number - 1].bound_left);
|
||||
|
||||
id = this->tokens[number - 1].type;
|
||||
}
|
||||
|
||||
size_t Context::Len() const
|
||||
{
|
||||
return token.size();
|
||||
}
|
||||
|
||||
bool Context::ValidateRegisterName(char c, size_t n) const
|
||||
{
|
||||
if (token[0] == c) {
|
||||
std::string_view p = token;
|
||||
|
||||
p.remove_prefix(1);
|
||||
|
||||
if (p.empty() || (p.size() > 1 && p[0] == '0')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (c != 'a') {
|
||||
for (const auto &ch : p) {
|
||||
if (std::isdigit(ch) == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (ToNumber(p) > n) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Context::ValidateParameterName(size_t number_of_params_already_is) const
|
||||
{
|
||||
if (number_of_params_already_is >= MAX_DWORD) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (token[0] == 'a') {
|
||||
std::string_view p = token;
|
||||
|
||||
p.remove_prefix(1);
|
||||
|
||||
if (ToNumber(p) == number_of_params_already_is) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string_view Context::GiveToken()
|
||||
{
|
||||
return token;
|
||||
}
|
||||
|
||||
Token::Type Context::Next()
|
||||
{
|
||||
if (this->tokens.size() > number) {
|
||||
return this->tokens[number].type;
|
||||
}
|
||||
|
||||
return this->tokens[number - 1].type;
|
||||
}
|
||||
|
||||
void Context::UpSignOperation()
|
||||
{
|
||||
signop = id;
|
||||
}
|
||||
|
||||
Token::Type Context::WaitFor()
|
||||
{
|
||||
return signop;
|
||||
}
|
||||
|
||||
bool Context::Mask()
|
||||
{
|
||||
return end;
|
||||
}
|
||||
|
||||
bool Context::NextMask()
|
||||
{
|
||||
if (end) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this->tokens.size() < number + 1;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(cert-dcl21-cpp)
|
||||
Token::Type Context::operator++(int)
|
||||
{
|
||||
Token::Type last_id = id;
|
||||
|
||||
if (this->tokens.size() > number) {
|
||||
++number;
|
||||
|
||||
id = this->tokens[number - 1].type;
|
||||
|
||||
token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left),
|
||||
tokens[number - 1].bound_right - tokens[number - 1].bound_left);
|
||||
} else {
|
||||
end = true;
|
||||
}
|
||||
|
||||
return last_id;
|
||||
}
|
||||
|
||||
Token::Type Context::operator++()
|
||||
{
|
||||
if (this->tokens.size() > number) {
|
||||
++number;
|
||||
|
||||
id = this->tokens[number - 1].type;
|
||||
|
||||
token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left),
|
||||
tokens[number - 1].bound_right - tokens[number - 1].bound_left);
|
||||
} else {
|
||||
end = true;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(cert-dcl21-cpp)
|
||||
Token::Type Context::operator--(int)
|
||||
{
|
||||
Token::Type last_id = id;
|
||||
|
||||
if (1 < number) {
|
||||
end = false;
|
||||
|
||||
--number;
|
||||
|
||||
id = this->tokens[number - 1].type;
|
||||
|
||||
token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left),
|
||||
tokens[number - 1].bound_right - tokens[number - 1].bound_left);
|
||||
} else {
|
||||
end = false;
|
||||
}
|
||||
|
||||
return last_id;
|
||||
}
|
||||
|
||||
Token::Type Context::operator--()
|
||||
{
|
||||
if (1 < number) {
|
||||
end = false;
|
||||
|
||||
--number;
|
||||
|
||||
id = this->tokens[number - 1].type;
|
||||
|
||||
token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left),
|
||||
tokens[number - 1].bound_right - tokens[number - 1].bound_left);
|
||||
} else {
|
||||
end = false;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
Token::Type Context::operator*()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
52
static_core/assembler/define.h
Normal file
52
static_core/assembler/define.h
Normal file
@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_DEFINE_HPP
|
||||
#define _PANDA_ASSEMBLER_DEFINE_HPP
|
||||
|
||||
/* Implementation-specific defines */
|
||||
|
||||
constexpr char PARSE_COMMENT_MARKER = '#';
|
||||
|
||||
constexpr char PARSE_AREA_MARKER = '.';
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define PANDA_ASSEMBLER_TYPES(_) \
|
||||
_("void", VOID) \
|
||||
_("u1", U1) \
|
||||
_("u8", U8) \
|
||||
_("i8", I8) \
|
||||
_("u16", U16) \
|
||||
_("i16", I16) \
|
||||
_("u32", U32) \
|
||||
_("i32", I32) \
|
||||
_("u64", U64) \
|
||||
_("i64", I64) \
|
||||
_("f32", F32) \
|
||||
_("f64", F64) \
|
||||
_("any", TAGGED)
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define KEYWORDS_LIST(_) \
|
||||
_(".catch", CATCH) \
|
||||
_(".catchall", CATCHALL) \
|
||||
_(".language", LANG) \
|
||||
_(".function", FUN) \
|
||||
_(".union_field", UNION) \
|
||||
_(".record", REC) \
|
||||
_(".array", ARR) \
|
||||
_(".field", FLD)
|
||||
|
||||
#endif /* !_PANDA_ASSEMBLER_DEFINE_HPP */
|
136
static_core/assembler/error.h
Normal file
136
static_core/assembler/error.h
Normal file
@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_ERROR_HPP
|
||||
#define _PANDA_ASSEMBLER_ERROR_HPP
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
// NOLINTBEGIN(misc-non-private-member-variables-in-classes)
|
||||
struct Error {
|
||||
enum class ErrorClass { WARNING = 0, ERROR };
|
||||
enum class ErrorType {
|
||||
ERR_NONE = 0,
|
||||
|
||||
// Lexer
|
||||
ERR_STRING_MISSING_TERMINATING_CHARACTER,
|
||||
|
||||
// Parser
|
||||
ERR_BAD_LABEL,
|
||||
ERR_BAD_LABEL_EXT,
|
||||
ERR_BAD_NAME_ID,
|
||||
ERR_BAD_NAME_REG,
|
||||
ERR_BAD_INTEGER_NAME,
|
||||
ERR_BAD_INTEGER_WIDTH,
|
||||
ERR_BAD_FLOAT_NAME,
|
||||
ERR_BAD_FLOAT_WIDTH,
|
||||
ERR_BAD_NUMBER_OPERANDS,
|
||||
ERR_BAD_OPERAND,
|
||||
ERR_BAD_OPERATION_NAME,
|
||||
ERR_BAD_NONEXISTING_OPERATION,
|
||||
ERR_BAD_ID_FUNCTION,
|
||||
ERR_BAD_ID_RECORD,
|
||||
ERR_BAD_ID_ARRAY,
|
||||
ERR_BAD_ID_FIELD,
|
||||
ERR_BAD_FUNCTION_NAME,
|
||||
ERR_BAD_RECORD_NAME,
|
||||
ERR_BAD_ARRAY_NAME,
|
||||
ERR_BAD_DEFINITION_METADATA,
|
||||
ERR_BAD_DEFINITION_FUNCTION,
|
||||
ERR_BAD_DEFINITION_RECORD,
|
||||
ERR_BAD_METADATA_BOUND,
|
||||
ERR_BAD_METADATA_UNKNOWN_ATTRIBUTE,
|
||||
ERR_BAD_METADATA_INVALID_VALUE,
|
||||
ERR_BAD_METADATA_MISSING_ATTRIBUTE,
|
||||
ERR_BAD_METADATA_MISSING_VALUE,
|
||||
ERR_BAD_METADATA_UNEXPECTED_ATTRIBUTE,
|
||||
ERR_BAD_METADATA_UNEXPECTED_VALUE,
|
||||
ERR_BAD_METADATA_MULTIPLE_ATTRIBUTE,
|
||||
ERR_BAD_FUNCTION_PARAMETERS,
|
||||
ERR_BAD_FUNCTION_RETURN_VALUE,
|
||||
ERR_FUNCTION_ARGUMENT_MISMATCH,
|
||||
ERR_BAD_FIELD_MISSING_NAME,
|
||||
ERR_BAD_FIELD_VALUE_TYPE,
|
||||
ERR_BAD_FIELD_METADATA,
|
||||
ERR_BAD_ARRAY_TYPE,
|
||||
ERR_BAD_ARRAY_SIZE,
|
||||
ERR_BAD_ARRAY_SIZE_VALUE,
|
||||
ERR_BAD_ARRAY_ELEMENT_MISSING_VALUE,
|
||||
ERR_BAD_ARRAY_ELEMENT_VALUE_TYPE,
|
||||
ERR_BAD_ARRAY_ELEMENT_VALUE,
|
||||
ERR_BAD_ARRAY_ELEMENT_VALUE_INTEGER,
|
||||
ERR_BAD_ARRAY_ELEMENT_VALUE_FLOAT,
|
||||
ERR_BAD_ARRAY_ELEMENT_VALUE_STRING,
|
||||
ERR_BAD_CHARACTER,
|
||||
ERR_BAD_KEYWORD,
|
||||
ERR_BAD_DEFINITION,
|
||||
ERR_BAD_BOUND,
|
||||
ERR_BAD_END,
|
||||
ERR_BAD_CLOSE,
|
||||
ERR_BAD_ARGS_BOUND,
|
||||
ERR_BAD_TYPE,
|
||||
ERR_BAD_PARAM_NAME,
|
||||
ERR_BAD_NOEXP_DELIM,
|
||||
ERR_BAD_STRING_INVALID_HEX_ESCAPE_SEQUENCE,
|
||||
ERR_BAD_STRING_UNKNOWN_ESCAPE_SEQUENCE,
|
||||
ERR_BAD_ARRAY_TYPE_BOUND,
|
||||
ERR_UNDEFINED_TYPE,
|
||||
ERR_MULTIPLE_DIRECTIVES,
|
||||
ERR_INCORRECT_DIRECTIVE_LOCATION,
|
||||
ERR_BAD_DIRECTIVE_DECLARATION,
|
||||
ERR_UNKNOWN_LANGUAGE,
|
||||
ERR_BAD_MNEMONIC_NAME,
|
||||
ERR_REPEATING_FIELD_NAME,
|
||||
ERR_FUNCTION_MULTIPLE_ALTERNATIVES,
|
||||
ERR_BAD_SIGNATURE,
|
||||
ERR_BAD_SIGNATURE_PARAMETERS,
|
||||
|
||||
// Warnings
|
||||
WAR_UNEXPECTED_RETURN_TYPE,
|
||||
WAR_UNEXPECTED_TYPE_ID,
|
||||
};
|
||||
|
||||
ErrorClass type;
|
||||
std::string whole_line;
|
||||
size_t pos; /* positions to highlight the word */
|
||||
size_t end;
|
||||
ErrorType err;
|
||||
std::string message;
|
||||
std::string verbose;
|
||||
size_t line_number;
|
||||
|
||||
inline Error() : Error("No messages", 0, ErrorType::ERR_NONE, "", 0, 0, "") {}
|
||||
|
||||
inline Error(std::string s, size_t line, ErrorType error_type, std::string overinfo, size_t p, size_t e,
|
||||
std::string buff, ErrorClass class_type = ErrorClass::ERROR)
|
||||
: type(class_type),
|
||||
whole_line(std::move(buff)),
|
||||
pos(p),
|
||||
end(e),
|
||||
err(error_type),
|
||||
message(std::move(s)),
|
||||
verbose(std::move(overinfo)),
|
||||
line_number(line)
|
||||
{
|
||||
}
|
||||
};
|
||||
// NOLINTEND(misc-non-private-member-variables-in-classes)
|
||||
|
||||
using ErrorList = std::vector<Error>;
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_ERROR_HPP
|
@ -0,0 +1,30 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
set(REGISTER_EXTENSIONS_H ${PANDA_BINARY_ROOT}/assembler/register_extensions.h)
|
||||
panda_gen_file(
|
||||
DATAFILE ${GEN_PLUGIN_OPTIONS_YAML}
|
||||
TEMPLATE ${PANDA_ROOT}/assembler/extensions/register_extensions.h.erb
|
||||
REQUIRES ${PANDA_ROOT}/templates/plugin_options.rb
|
||||
EXTRA_DEPENDENCIES plugin_options_merge
|
||||
OUTPUTFILE ${REGISTER_EXTENSIONS_H}
|
||||
)
|
||||
|
||||
add_custom_target(assembler_extensions DEPENDS
|
||||
plugin_options_gen
|
||||
${REGISTER_EXTENSIONS_H}
|
||||
)
|
||||
|
||||
add_dependencies(arkassembler_obj assembler_extensions)
|
||||
add_dependencies(panda_gen_files assembler_extensions)
|
22
static_core/assembler/extensions/extensions.cpp
Normal file
22
static_core/assembler/extensions/extensions.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "extensions.h"
|
||||
#include "macros.h"
|
||||
#include "register_extensions.h"
|
||||
|
||||
namespace panda::pandasm::extensions {
|
||||
|
||||
} // namespace panda::pandasm::extensions
|
45
static_core/assembler/extensions/extensions.h
Normal file
45
static_core/assembler/extensions/extensions.h
Normal file
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_ASSEMBLER_EXTENSIONS_H_
|
||||
#define PANDA_ASSEMBLER_EXTENSIONS_H_
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
|
||||
#include "meta.h"
|
||||
#include "libpandafile/file_items.h"
|
||||
#include "libpandabase/macros.h"
|
||||
|
||||
namespace panda::pandasm::extensions {
|
||||
|
||||
// Workaround for ts2abc. Should be removed by our colleagues.
|
||||
using Language = panda::panda_file::SourceLang;
|
||||
|
||||
class MetadataExtension {
|
||||
public:
|
||||
static PANDA_PUBLIC_API std::unique_ptr<RecordMetadata> CreateRecordMetadata(panda::panda_file::SourceLang lang);
|
||||
|
||||
static PANDA_PUBLIC_API std::unique_ptr<FieldMetadata> CreateFieldMetadata(panda::panda_file::SourceLang lang);
|
||||
|
||||
static PANDA_PUBLIC_API std::unique_ptr<FunctionMetadata> CreateFunctionMetadata(
|
||||
panda::panda_file::SourceLang lang);
|
||||
|
||||
static PANDA_PUBLIC_API std::unique_ptr<ParamMetadata> CreateParamMetadata(panda::panda_file::SourceLang lang);
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm::extensions
|
||||
|
||||
#endif // PANDA_ASSEMBLER_EXTENSIONS_H_
|
54
static_core/assembler/extensions/register_extensions.h.erb
Normal file
54
static_core/assembler/extensions/register_extensions.h.erb
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_ASSEMBLER_EXTENSIONS_REGISTER_EXTENSIONS_H
|
||||
#define PANDA_ASSEMBLER_EXTENSIONS_REGISTER_EXTENSIONS_H
|
||||
|
||||
#include "extensions/extensions.h"
|
||||
|
||||
% Common::plugins.each_value do |plugin_opts|
|
||||
% next unless plugin_opts["Metadatas"]
|
||||
% plugin_opts["Metadatas"].each_value do |new_class_opts|
|
||||
// NOLINTNEXTLINE(readability-duplicate-include)
|
||||
#include "<%= new_class_opts["header_path"] %>"
|
||||
% end
|
||||
% end
|
||||
|
||||
namespace panda::pandasm::extensions {
|
||||
|
||||
// NOLINTBEGIN(misc-definitions-in-headers)
|
||||
|
||||
%["RecordMetadata", "FieldMetadata", "FunctionMetadata", "ParamMetadata"].each do |metadata|
|
||||
/* static */
|
||||
std::unique_ptr<<%= metadata %>> MetadataExtension::Create<%= metadata %>([[maybe_unused]] panda::panda_file::SourceLang lang)
|
||||
{
|
||||
% Common::plugins.each_value do |plugin_opts|
|
||||
% next unless plugin_opts["Metadatas"]
|
||||
% next unless plugin_opts["Metadatas"][metadata]
|
||||
if (lang == <%= plugin_opts["lang_enum"] %>) {
|
||||
return std::make_unique <<%= plugin_opts["Metadatas"][metadata]["new_class_name"] %>>();
|
||||
}
|
||||
% end
|
||||
|
||||
return std::make_unique<<%= metadata %>>();
|
||||
}
|
||||
|
||||
% end
|
||||
|
||||
// NOLINTEND(misc-definitions-in-headers)
|
||||
|
||||
} // namespace panda::pandasm::extensions
|
||||
|
||||
#endif // PANDA_ASSEMBLER_EXTENSIONS_REGISTER_EXTENSIONS_H
|
88
static_core/assembler/ide_helpers.h
Normal file
88
static_core/assembler/ide_helpers.h
Normal file
@ -0,0 +1,88 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_ASSEMBLER_IDE_HELPERS_H
|
||||
#define PANDA_ASSEMBLER_IDE_HELPERS_H
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
// NOLINTBEGIN(misc-non-private-member-variables-in-classes)
|
||||
struct SourcePosition {
|
||||
size_t line = 0;
|
||||
size_t column = 0;
|
||||
|
||||
std::string JsonSerialize() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "{ "
|
||||
<< "\"line\": " << line << ", "
|
||||
<< "\"column\": " << column << " }";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
|
||||
struct SourceLocation {
|
||||
SourcePosition begin;
|
||||
SourcePosition end;
|
||||
|
||||
std::string JsonSerialize() const
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "{ "
|
||||
<< "\"begin\": " << begin.JsonSerialize() << ", "
|
||||
<< "\"end\": " << end.JsonSerialize() << " }";
|
||||
return ss.str();
|
||||
}
|
||||
};
|
||||
// NOLINTEND(misc-non-private-member-variables-in-classes)
|
||||
|
||||
template <typename T>
|
||||
std::string JsonSerializeItemBody(const T &item)
|
||||
{
|
||||
std::stringstream ss;
|
||||
std::string quoted_name = "\"" + item.name + "\"";
|
||||
ss << "{ "
|
||||
<< "\"name\": " << quoted_name;
|
||||
if (item.file_location->is_defined) {
|
||||
ss << ", "
|
||||
<< "\"bodyLocation\": " << item.body_location.JsonSerialize() << " }";
|
||||
} else {
|
||||
ss << " }";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::string JsonSerializeProgramItems(const T &item_table)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "[ ";
|
||||
auto it = item_table.begin();
|
||||
if (it != item_table.end()) {
|
||||
ss << JsonSerializeItemBody(it->second);
|
||||
++it;
|
||||
}
|
||||
while (it != item_table.end()) {
|
||||
ss << ", " << JsonSerializeItemBody(it->second);
|
||||
++it;
|
||||
}
|
||||
ss << " ]";
|
||||
return ss.str();
|
||||
}
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_IDE_HELPERS_H
|
405
static_core/assembler/lexer.cpp
Normal file
405
static_core/assembler/lexer.cpp
Normal file
@ -0,0 +1,405 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "lexer.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
/*-------------------------------*/
|
||||
|
||||
/* Is this a delimiter ? */
|
||||
Token::Type FindDelim(char c)
|
||||
{
|
||||
/* The map of delimiters */
|
||||
static const std::unordered_map<char, Token::Type> DELIM = {{',', Token::Type::DEL_COMMA},
|
||||
{':', Token::Type::DEL_COLON},
|
||||
{'{', Token::Type::DEL_BRACE_L},
|
||||
{'}', Token::Type::DEL_BRACE_R},
|
||||
{'(', Token::Type::DEL_BRACKET_L},
|
||||
{')', Token::Type::DEL_BRACKET_R},
|
||||
{'<', Token::Type::DEL_LT},
|
||||
{'>', Token::Type::DEL_GT},
|
||||
{'=', Token::Type::DEL_EQ},
|
||||
{'[', Token::Type::DEL_SQUARE_BRACKET_L},
|
||||
{']', Token::Type::DEL_SQUARE_BRACKET_R}};
|
||||
|
||||
auto iter = DELIM.find(c);
|
||||
|
||||
if (iter == DELIM.end()) {
|
||||
return Token::Type::ID_BAD;
|
||||
}
|
||||
|
||||
return DELIM.at(c);
|
||||
}
|
||||
|
||||
Token::Type FindOperation(std::string_view s)
|
||||
{
|
||||
/* Generate the map of OPERATIONS from ISA: */
|
||||
static const std::unordered_map<std::string_view, Token::Type> OPERATIONS = {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define OPLIST(inst_code, name, optype, width, flags, dst_idx, use_idxs, prof_size) \
|
||||
{std::string_view(name), Token::Type::ID_OP_##inst_code},
|
||||
PANDA_INSTRUCTION_LIST(OPLIST)
|
||||
#undef OPLIST
|
||||
};
|
||||
|
||||
auto iter = OPERATIONS.find(s);
|
||||
|
||||
if (iter == OPERATIONS.end()) {
|
||||
return Token::Type::ID_BAD;
|
||||
}
|
||||
|
||||
return OPERATIONS.at(s);
|
||||
}
|
||||
|
||||
Token::Type Findkeyword(std::string_view s)
|
||||
{
|
||||
/* Generate the map of KEYWORDS: */
|
||||
static const std::unordered_map<std::string_view, Token::Type> KEYWORDS = {
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define KEYWORDS(name, inst_code) {std::string_view(name), Token::Type::ID_##inst_code},
|
||||
KEYWORDS_LIST(KEYWORDS)
|
||||
#undef KEYWORDS
|
||||
};
|
||||
|
||||
auto iter = KEYWORDS.find(s);
|
||||
|
||||
if (iter == KEYWORDS.end()) {
|
||||
return Token::Type::ID_BAD;
|
||||
}
|
||||
|
||||
return KEYWORDS.at(s);
|
||||
}
|
||||
|
||||
std::string_view TokenTypeWhat(Token::Type t)
|
||||
{
|
||||
if (t >= Token::Type::OPERATION && t < Token::Type::KEYWORD) {
|
||||
return "OPERATION";
|
||||
}
|
||||
|
||||
if (t >= Token::Type::KEYWORD) {
|
||||
return "KEYWORD";
|
||||
}
|
||||
|
||||
switch (t) {
|
||||
case Token::Type::ID_BAD: {
|
||||
return "ID_BAD";
|
||||
}
|
||||
case Token::Type::DEL_COMMA: {
|
||||
return "DEL_COMMA";
|
||||
}
|
||||
case Token::Type::DEL_COLON: {
|
||||
return "DEL_COLON";
|
||||
}
|
||||
case Token::Type::DEL_BRACE_L: {
|
||||
return "DEL_BRACE_L";
|
||||
}
|
||||
case Token::Type::DEL_BRACE_R: {
|
||||
return "DEL_BRACE_R";
|
||||
}
|
||||
case Token::Type::DEL_BRACKET_L: {
|
||||
return "DEL_BRACKET_L";
|
||||
}
|
||||
case Token::Type::DEL_BRACKET_R: {
|
||||
return "DEL_BRACKET_R";
|
||||
}
|
||||
case Token::Type::DEL_SQUARE_BRACKET_L: {
|
||||
return "DEL_SQUARE_BRACKET_L";
|
||||
}
|
||||
case Token::Type::DEL_SQUARE_BRACKET_R: {
|
||||
return "DEL_SQUARE_BRACKET_R";
|
||||
}
|
||||
case Token::Type::DEL_GT: {
|
||||
return "DEL_GT";
|
||||
}
|
||||
case Token::Type::DEL_LT: {
|
||||
return "DEL_LT";
|
||||
}
|
||||
case Token::Type::DEL_EQ: {
|
||||
return "DEL_EQ";
|
||||
}
|
||||
case Token::Type::DEL_DOT: {
|
||||
return "DEL_DOT";
|
||||
}
|
||||
case Token::Type::ID: {
|
||||
return "ID";
|
||||
}
|
||||
case Token::Type::ID_STRING: {
|
||||
return "ID_STRING";
|
||||
}
|
||||
default:
|
||||
return "NONE";
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsQuote(char c)
|
||||
{
|
||||
return c == '"';
|
||||
}
|
||||
|
||||
Lexer::Lexer()
|
||||
{
|
||||
LOG(DEBUG, ASSEMBLER) << "element of class Lexer initialized";
|
||||
}
|
||||
|
||||
Lexer::~Lexer()
|
||||
{
|
||||
LOG(DEBUG, ASSEMBLER) << "element of class Lexer destructed";
|
||||
}
|
||||
|
||||
Tokens Lexer::TokenizeString(const std::string &source_str)
|
||||
{
|
||||
LOG(DEBUG, ASSEMBLER) << "started tokenizing of line " << lines_.size() + 1 << ": ";
|
||||
|
||||
lines_.emplace_back(source_str);
|
||||
|
||||
curr_line_ = &lines_.back();
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << std::string_view(&*(curr_line_->buffer.begin() + curr_line_->pos),
|
||||
curr_line_->end - curr_line_->pos);
|
||||
|
||||
AnalyzeLine();
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "tokenization of line " << lines_.size() << " is successful";
|
||||
LOG(DEBUG, ASSEMBLER) << " tokens identified: ";
|
||||
|
||||
for (const auto &f_i : lines_.back().tokens) {
|
||||
LOG(DEBUG, ASSEMBLER) << "\n "
|
||||
<< std::string_view(&*(f_i.whole_line.begin() + f_i.bound_left),
|
||||
f_i.bound_right - f_i.bound_left)
|
||||
<< " (type: " << TokenTypeWhat(f_i.type) << ")";
|
||||
|
||||
LOG(DEBUG, ASSEMBLER);
|
||||
LOG(DEBUG, ASSEMBLER);
|
||||
}
|
||||
return std::pair<std::vector<Token>, Error>(lines_.back().tokens, err_);
|
||||
}
|
||||
|
||||
/* End of line? */
|
||||
bool Lexer::Eol() const
|
||||
{
|
||||
return curr_line_->pos == curr_line_->end;
|
||||
}
|
||||
|
||||
/* Return the type of token */
|
||||
Token::Type Lexer::LexGetType(size_t beg, size_t end) const
|
||||
{
|
||||
if (FindDelim(curr_line_->buffer[beg]) != Token::Type::ID_BAD) { /* delimiter */
|
||||
return FindDelim(curr_line_->buffer[beg]);
|
||||
}
|
||||
|
||||
std::string_view p(&*(curr_line_->buffer.begin() + beg), end - beg);
|
||||
|
||||
Token::Type type = Findkeyword(p);
|
||||
|
||||
if (type != Token::Type::ID_BAD) {
|
||||
return type;
|
||||
}
|
||||
|
||||
type = FindOperation(p);
|
||||
|
||||
if (type != Token::Type::ID_BAD) {
|
||||
return type;
|
||||
}
|
||||
|
||||
if (IsQuote(curr_line_->buffer[beg])) {
|
||||
return Token::Type::ID_STRING;
|
||||
}
|
||||
|
||||
return Token::Type::ID; /* other */
|
||||
}
|
||||
|
||||
/* Handle string literal */
|
||||
bool Lexer::LexString()
|
||||
{
|
||||
bool is_escape_seq = false;
|
||||
char quote = curr_line_->buffer[curr_line_->pos];
|
||||
size_t begin = curr_line_->pos;
|
||||
while (!Eol()) {
|
||||
++(curr_line_->pos);
|
||||
|
||||
char c = curr_line_->buffer[curr_line_->pos];
|
||||
|
||||
if (is_escape_seq) {
|
||||
is_escape_seq = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\\') {
|
||||
is_escape_seq = true;
|
||||
}
|
||||
|
||||
if (c == quote) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_line_->buffer[curr_line_->pos] != quote) {
|
||||
err_ = Error(std::string("Missing terminating ") + quote + " character", 0,
|
||||
Error::ErrorType::ERR_STRING_MISSING_TERMINATING_CHARACTER, "", begin, curr_line_->pos,
|
||||
curr_line_->buffer);
|
||||
return false;
|
||||
}
|
||||
|
||||
++(curr_line_->pos);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tokens handling: set a corresponding
|
||||
* elements bound_left and bound_right of the array tokens
|
||||
* to the first and last characters of a corresponding token.
|
||||
*
|
||||
* bound_r1 bound_r2 bound_r3
|
||||
* | | |
|
||||
* v v v
|
||||
* token1 token2 token3 ... token1 token2 token3 ...
|
||||
* => ^ ^ ^
|
||||
* | | |
|
||||
* bound1 bound2 bound3 ... bound_l1 bound_l2 bound_l3 ...
|
||||
*
|
||||
*/
|
||||
void Lexer::LexTokens()
|
||||
{
|
||||
if (Eol()) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "token search started (line " << lines_.size() << "): "
|
||||
<< std::string_view(&*(curr_line_->buffer.begin() + curr_line_->pos),
|
||||
curr_line_->end - curr_line_->pos);
|
||||
|
||||
while (curr_line_->end > curr_line_->pos && isspace(curr_line_->buffer[curr_line_->end - 1]) != 0) {
|
||||
--(curr_line_->end);
|
||||
}
|
||||
|
||||
while (isspace(curr_line_->buffer[curr_line_->pos]) != 0 && !Eol()) {
|
||||
++(curr_line_->pos);
|
||||
}
|
||||
|
||||
size_t bound_right;
|
||||
|
||||
size_t bound_left;
|
||||
|
||||
while (!Eol()) {
|
||||
bound_left = curr_line_->pos;
|
||||
|
||||
if (FindDelim(curr_line_->buffer[curr_line_->pos]) != Token::Type::ID_BAD) {
|
||||
++(curr_line_->pos);
|
||||
} else if (IsQuote(curr_line_->buffer[curr_line_->pos])) {
|
||||
if (!LexString()) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
while (!Eol() && FindDelim(curr_line_->buffer[curr_line_->pos]) == Token::Type::ID_BAD &&
|
||||
isspace(curr_line_->buffer[curr_line_->pos]) == 0) {
|
||||
++(curr_line_->pos);
|
||||
size_t position = curr_line_->pos;
|
||||
while (FindDelim(curr_line_->buffer[position]) == Token::Type::DEL_SQUARE_BRACKET_L ||
|
||||
FindDelim(curr_line_->buffer[position]) == Token::Type::DEL_SQUARE_BRACKET_R) {
|
||||
position++;
|
||||
}
|
||||
if (isspace(curr_line_->buffer[position]) == 0 && (position != curr_line_->end)) {
|
||||
curr_line_->pos = position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bound_right = curr_line_->pos;
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "token identified (line " << lines_.size() << ", "
|
||||
<< "token " << curr_line_->tokens.size() + 1 << "): "
|
||||
<< std::string_view(&*(curr_line_->buffer.begin() + bound_left), bound_right - bound_left)
|
||||
<< " ("
|
||||
<< "type: " << TokenTypeWhat(LexGetType(bound_left, bound_right)) << ")";
|
||||
|
||||
curr_line_->tokens.emplace_back(bound_left, bound_right, LexGetType(bound_left, bound_right),
|
||||
curr_line_->buffer);
|
||||
|
||||
while (isspace(curr_line_->buffer[curr_line_->pos]) != 0 && !Eol()) {
|
||||
++(curr_line_->pos);
|
||||
}
|
||||
}
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "all tokens identified (line " << lines_.size() << ")";
|
||||
}
|
||||
|
||||
/*
|
||||
* Ignore comments:
|
||||
* find PARSE_COMMENT_MARKER and move line->end
|
||||
* to another position (next after the last character of the last
|
||||
* significant (this is no a comment) element in a current
|
||||
* line: line->buffer).
|
||||
*
|
||||
* Ex:
|
||||
* [Label:] operation operand[,operand] [# comment]
|
||||
*
|
||||
* L1: mov v0, v1 # moving! L1: mov v0, v1 # moving!
|
||||
* ^ => ^
|
||||
* | |
|
||||
* end end
|
||||
*/
|
||||
void Lexer::LexPreprocess()
|
||||
{
|
||||
LOG(DEBUG, ASSEMBLER) << "started removing comments (line " << lines_.size() << "): "
|
||||
<< std::string_view(&*(curr_line_->buffer.begin() + curr_line_->pos),
|
||||
curr_line_->end - curr_line_->pos);
|
||||
|
||||
// Searching for comment marker located outside of string literals.
|
||||
bool inside_str_lit = !curr_line_->buffer.empty() && curr_line_->buffer[0] == '\"';
|
||||
size_t cmt_pos = curr_line_->buffer.find_first_of("\"#", 0);
|
||||
if (cmt_pos != std::string::npos) {
|
||||
do {
|
||||
if (cmt_pos != 0 && curr_line_->buffer[cmt_pos - 1] != '\\' && curr_line_->buffer[cmt_pos] == '\"') {
|
||||
inside_str_lit = !inside_str_lit;
|
||||
} else if (curr_line_->buffer[cmt_pos] == PARSE_COMMENT_MARKER && !inside_str_lit) {
|
||||
break;
|
||||
}
|
||||
} while ((cmt_pos = curr_line_->buffer.find_first_of("\"#", cmt_pos + 1)) != std::string::npos);
|
||||
}
|
||||
|
||||
if (cmt_pos != std::string::npos) {
|
||||
curr_line_->end = cmt_pos;
|
||||
}
|
||||
|
||||
while (curr_line_->end > curr_line_->pos && isspace(curr_line_->buffer[curr_line_->end - 1]) != 0) {
|
||||
--(curr_line_->end);
|
||||
}
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "comments removed (line " << lines_.size() << "): "
|
||||
<< std::string_view(&*(curr_line_->buffer.begin() + curr_line_->pos),
|
||||
curr_line_->end - curr_line_->pos);
|
||||
}
|
||||
|
||||
void Lexer::SkipSpace()
|
||||
{
|
||||
while (!Eol() && isspace(curr_line_->buffer[curr_line_->pos]) != 0) {
|
||||
++(curr_line_->pos);
|
||||
}
|
||||
}
|
||||
|
||||
void Lexer::AnalyzeLine()
|
||||
{
|
||||
LexPreprocess();
|
||||
|
||||
SkipSpace();
|
||||
|
||||
LexTokens();
|
||||
}
|
||||
|
||||
/*-------------------------------*/
|
||||
|
||||
} // namespace panda::pandasm
|
128
static_core/assembler/lexer.h
Normal file
128
static_core/assembler/lexer.h
Normal file
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_LEXER_HPP
|
||||
#define _PANDA_ASSEMBLER_LEXER_HPP
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "define.h"
|
||||
#include "error.h"
|
||||
#include "isa.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
// NOLINTBEGIN(misc-non-private-member-variables-in-classes)
|
||||
struct Token {
|
||||
enum class Type {
|
||||
ID_BAD = 0,
|
||||
/* delimiters */
|
||||
DEL_COMMA, /* , */
|
||||
DEL_COLON, /* : */
|
||||
DEL_BRACE_L, /* { */
|
||||
DEL_BRACE_R, /* } */
|
||||
DEL_BRACKET_L, /* ( */
|
||||
DEL_BRACKET_R, /* ) */
|
||||
DEL_SQUARE_BRACKET_L, /* [ */
|
||||
DEL_SQUARE_BRACKET_R, /* ] */
|
||||
DEL_GT, /* > */
|
||||
DEL_LT, /* < */
|
||||
DEL_EQ, /* = */
|
||||
DEL_DOT, /* . */
|
||||
ID, /* other */
|
||||
ID_STRING, /* string literal */
|
||||
OPERATION, /* special */
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define OPLIST(inst_code, name, optype, width, flags, dst_idx, src_idxs, prof_size) \
|
||||
ID_OP_##inst_code, /* command type list */
|
||||
PANDA_INSTRUCTION_LIST(OPLIST)
|
||||
#undef OPLIST
|
||||
KEYWORD, /* special */
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define KEYWORDS(name, inst_code) ID_##inst_code, /* keyword type List */
|
||||
KEYWORDS_LIST(KEYWORDS)
|
||||
#undef KEYWORDS
|
||||
};
|
||||
|
||||
std::string whole_line;
|
||||
size_t bound_left; /* right and left bounds of tokens */
|
||||
size_t bound_right;
|
||||
Type type;
|
||||
|
||||
Token() : Token(0, 0, Type::ID_BAD, "") {}
|
||||
|
||||
Token(size_t b_l, size_t b_r, Type t, std::string beg_of_line)
|
||||
: whole_line(std::move(beg_of_line)), bound_left(b_l), bound_right(b_r), type(t)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
using Tokens = std::pair<std::vector<Token>, Error>;
|
||||
|
||||
using TokenSet = const std::vector<std::vector<Token>>;
|
||||
|
||||
struct Line {
|
||||
std::vector<Token> tokens;
|
||||
std::string buffer; /* Raw line, as read from the file */
|
||||
size_t pos {0}; /* current line position */
|
||||
size_t end;
|
||||
|
||||
explicit Line(std::string str) : buffer(std::move(str)), end(buffer.size()) {}
|
||||
};
|
||||
// NOLINTEND(misc-non-private-member-variables-in-classes)
|
||||
|
||||
class Lexer {
|
||||
public:
|
||||
PANDA_PUBLIC_API Lexer();
|
||||
PANDA_PUBLIC_API ~Lexer();
|
||||
NO_MOVE_SEMANTIC(Lexer);
|
||||
NO_COPY_SEMANTIC(Lexer);
|
||||
|
||||
/*
|
||||
* The main function of Tokenizing, which takes a string.
|
||||
* Returns a vector of tokens.
|
||||
*/
|
||||
PANDA_PUBLIC_API Tokens TokenizeString(const std::string &source_str);
|
||||
|
||||
private:
|
||||
std::vector<Line> lines_;
|
||||
Line *curr_line_ {nullptr};
|
||||
Error err_;
|
||||
|
||||
bool Eol() const; /* End of line */
|
||||
bool LexString();
|
||||
void LexTokens();
|
||||
void LexPreprocess();
|
||||
void SkipSpace();
|
||||
void AnalyzeLine();
|
||||
Token::Type LexGetType(size_t beg, size_t end) const;
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns a string representation of a token type.
|
||||
*/
|
||||
std::string_view TokenTypeWhat(Token::Type t);
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_LEXER_HPP
|
93
static_core/assembler/mangling.h
Normal file
93
static_core/assembler/mangling.h
Normal file
@ -0,0 +1,93 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_MANGLING_H
|
||||
#define _PANDA_ASSEMBLER_MANGLING_H
|
||||
|
||||
#include "assembly-function.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace panda::pandasm {
|
||||
constexpr const std::string_view MANGLE_BEGIN = ":";
|
||||
constexpr const std::string_view MANGLE_SEPARATOR = ";";
|
||||
|
||||
constexpr const std::string_view SIGNATURE_BEGIN = MANGLE_BEGIN;
|
||||
constexpr const std::string_view SIGNATURE_TYPES_SEPARATOR = ",";
|
||||
constexpr const std::string_view SIGNATURE_TYPES_SEPARATOR_L = "(";
|
||||
constexpr const std::string_view SIGNATURE_TYPES_SEPARATOR_R = ")";
|
||||
|
||||
inline std::string DeMangleName(const std::string &name)
|
||||
{
|
||||
auto iter = name.find_first_of(MANGLE_BEGIN);
|
||||
if (iter != std::string::npos) {
|
||||
return name.substr(0, name.find_first_of(MANGLE_BEGIN));
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
inline std::string MangleFunctionName(const std::string &name, const std::vector<pandasm::Function::Parameter> ¶ms,
|
||||
const pandasm::Type &return_type)
|
||||
{
|
||||
std::string mangle_name {name};
|
||||
mangle_name += MANGLE_BEGIN;
|
||||
for (const auto &p : params) {
|
||||
mangle_name += p.type.GetName() + std::string(MANGLE_SEPARATOR);
|
||||
}
|
||||
mangle_name += return_type.GetName() + std::string(MANGLE_SEPARATOR);
|
||||
|
||||
return mangle_name;
|
||||
}
|
||||
|
||||
inline std::string MangleFieldName(const std::string &name, const pandasm::Type &type)
|
||||
{
|
||||
std::string mangle_name {name};
|
||||
mangle_name += MANGLE_BEGIN;
|
||||
mangle_name += type.GetName() + std::string(MANGLE_SEPARATOR);
|
||||
return mangle_name;
|
||||
}
|
||||
|
||||
inline std::string GetFunctionSignatureFromName(std::string name,
|
||||
const std::vector<pandasm::Function::Parameter> ¶ms)
|
||||
{
|
||||
name += SIGNATURE_BEGIN;
|
||||
name += SIGNATURE_TYPES_SEPARATOR_L;
|
||||
|
||||
bool first = true;
|
||||
for (const auto &p : params) {
|
||||
name += (first) ? "" : SIGNATURE_TYPES_SEPARATOR;
|
||||
first = false;
|
||||
name += p.type.GetPandasmName();
|
||||
}
|
||||
|
||||
name += SIGNATURE_TYPES_SEPARATOR_R;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
inline std::string GetFunctionNameFromSignature(const std::string &sig)
|
||||
{
|
||||
return DeMangleName(sig);
|
||||
}
|
||||
|
||||
inline bool IsSignatureOrMangled(const std::string &str)
|
||||
{
|
||||
return str.find(SIGNATURE_BEGIN) != std::string::npos;
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_MANGLING_HPP
|
518
static_core/assembler/meta.cpp
Normal file
518
static_core/assembler/meta.cpp
Normal file
@ -0,0 +1,518 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "meta.h"
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
#include "utils/expected.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
std::optional<Metadata::Error> Metadata::ValidateSize(std::string_view value) const
|
||||
{
|
||||
constexpr size_t SIZE = 10;
|
||||
|
||||
if (!std::all_of(value.cbegin(), value.cend(), ::isdigit)) {
|
||||
return Error("Unsigned integer value expected", Error::Type::INVALID_VALUE);
|
||||
}
|
||||
|
||||
strtoul(value.data(), nullptr, SIZE);
|
||||
if (errno == ERANGE) {
|
||||
return Error("Value is out of range", Error::Type::INVALID_VALUE);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ItemMetadata::IsForeign() const
|
||||
{
|
||||
return GetAttribute("external");
|
||||
}
|
||||
|
||||
static panda::pandasm::Value::Type GetType(std::string_view value)
|
||||
{
|
||||
using VType = panda::pandasm::Value::Type;
|
||||
static std::unordered_map<std::string_view, VType> types {
|
||||
{"u1", VType::U1}, {"i8", VType::I8}, {"u8", VType::U8},
|
||||
{"i16", VType::I16}, {"u16", VType::U16}, {"i32", VType::I32},
|
||||
{"u32", VType::U32}, {"i64", VType::I64}, {"u64", VType::U64},
|
||||
{"f32", VType::F32}, {"f64", VType::F64}, {"string", VType::STRING},
|
||||
{"record", VType::RECORD}, {"enum", VType::ENUM}, {"annotation", VType::ANNOTATION},
|
||||
{"array", VType::ARRAY}, {"method", VType::METHOD}};
|
||||
|
||||
return types[value];
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static T ConvertFromString(std::string_view value, char **end)
|
||||
{
|
||||
static_assert(std::is_integral_v<T>, "T must be integral type");
|
||||
|
||||
constexpr T MIN = std::numeric_limits<T>::min();
|
||||
constexpr T MAX = std::numeric_limits<T>::max();
|
||||
|
||||
if constexpr (std::is_signed_v<T>) {
|
||||
auto v = ConvertFromString<int64_t>(value, end);
|
||||
if (v < MIN || v > MAX) {
|
||||
errno = ERANGE;
|
||||
}
|
||||
return static_cast<T>(v);
|
||||
}
|
||||
|
||||
if constexpr (!std::is_signed_v<T>) {
|
||||
auto v = ConvertFromString<uint64_t>(value, end);
|
||||
if (v < MIN || v > MAX) {
|
||||
errno = ERANGE;
|
||||
}
|
||||
return static_cast<T>(v);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
int64_t ConvertFromString(std::string_view value, char **end)
|
||||
{
|
||||
return static_cast<int64_t>(strtoll(value.data(), end, 0));
|
||||
}
|
||||
|
||||
template <>
|
||||
uint64_t ConvertFromString(std::string_view value, char **end)
|
||||
{
|
||||
return static_cast<uint64_t>(strtoull(value.data(), end, 0));
|
||||
}
|
||||
|
||||
template <>
|
||||
float ConvertFromString(std::string_view value, char **end)
|
||||
{
|
||||
return strtof(value.data(), end);
|
||||
}
|
||||
|
||||
template <>
|
||||
double ConvertFromString(std::string_view value, char **end)
|
||||
{
|
||||
return strtod(value.data(), end);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static Expected<T, Metadata::Error> ConvertFromString(std::string_view value)
|
||||
{
|
||||
static_assert(std::is_arithmetic_v<T>, "T must be arithmetic type");
|
||||
|
||||
char *end = nullptr;
|
||||
auto v = ConvertFromString<T>(value, &end);
|
||||
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
if (end != value.data() + value.length()) {
|
||||
return Unexpected(Metadata::Error("Excepted integer literal", Metadata::Error::Type::INVALID_VALUE));
|
||||
}
|
||||
|
||||
if (errno == ERANGE) {
|
||||
errno = 0;
|
||||
return Unexpected(Metadata::Error("Value is out of range", Metadata::Error::Type::INVALID_VALUE));
|
||||
}
|
||||
|
||||
return static_cast<T>(v);
|
||||
}
|
||||
|
||||
template <Value::Type TYPE, class T = ValueTypeHelperT<TYPE>>
|
||||
static Expected<ScalarValue, Metadata::Error> CreatePrimitiveValue(std::string_view value,
|
||||
T max_value = std::numeric_limits<T>::max())
|
||||
{
|
||||
auto res = ConvertFromString<T>(value);
|
||||
if (!res) {
|
||||
return Unexpected(res.Error());
|
||||
}
|
||||
|
||||
auto converted = res.Value();
|
||||
|
||||
if (converted > max_value) {
|
||||
return Unexpected(Metadata::Error("Value is out of range", Metadata::Error::Type::INVALID_VALUE));
|
||||
}
|
||||
|
||||
return ScalarValue::Create<TYPE>(converted);
|
||||
}
|
||||
|
||||
static Expected<ScalarValue, Metadata::Error> CreateValue(
|
||||
Value::Type type, std::string_view value,
|
||||
const std::unordered_map<std::string, std::unique_ptr<AnnotationData>> &annotation_id_map = {})
|
||||
{
|
||||
switch (type) {
|
||||
case Value::Type::U1: {
|
||||
return CreatePrimitiveValue<Value::Type::U1>(value, 1);
|
||||
}
|
||||
case Value::Type::I8: {
|
||||
return CreatePrimitiveValue<Value::Type::I8>(value);
|
||||
}
|
||||
case Value::Type::U8: {
|
||||
return CreatePrimitiveValue<Value::Type::U8>(value);
|
||||
}
|
||||
case Value::Type::I16: {
|
||||
return CreatePrimitiveValue<Value::Type::I16>(value);
|
||||
}
|
||||
case Value::Type::U16: {
|
||||
return CreatePrimitiveValue<Value::Type::U16>(value);
|
||||
}
|
||||
case Value::Type::I32: {
|
||||
return CreatePrimitiveValue<Value::Type::I32>(value);
|
||||
}
|
||||
case Value::Type::U32: {
|
||||
return CreatePrimitiveValue<Value::Type::U32>(value);
|
||||
}
|
||||
case Value::Type::I64: {
|
||||
return CreatePrimitiveValue<Value::Type::I64>(value);
|
||||
}
|
||||
case Value::Type::U64: {
|
||||
return CreatePrimitiveValue<Value::Type::U64>(value);
|
||||
}
|
||||
case Value::Type::F32: {
|
||||
return CreatePrimitiveValue<Value::Type::F32>(value);
|
||||
}
|
||||
case Value::Type::F64: {
|
||||
return CreatePrimitiveValue<Value::Type::F64>(value);
|
||||
}
|
||||
case Value::Type::STRING: {
|
||||
return ScalarValue::Create<Value::Type::STRING>(value);
|
||||
}
|
||||
case Value::Type::RECORD: {
|
||||
return ScalarValue::Create<Value::Type::RECORD>(Type::FromName(value));
|
||||
}
|
||||
case Value::Type::METHOD: {
|
||||
return ScalarValue::Create<Value::Type::METHOD>(value);
|
||||
}
|
||||
case Value::Type::ENUM: {
|
||||
return ScalarValue::Create<Value::Type::ENUM>(value);
|
||||
}
|
||||
case Value::Type::ANNOTATION: {
|
||||
auto it = annotation_id_map.find(std::string(value));
|
||||
if (it == annotation_id_map.cend()) {
|
||||
return Unexpected(Metadata::Error("Unknown annotation id", Metadata::Error::Type::INVALID_VALUE));
|
||||
}
|
||||
|
||||
auto annotation_value = it->second.get();
|
||||
return ScalarValue::Create<Value::Type::ANNOTATION>(*annotation_value);
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::AnnotationElementBuilder::AddValue(
|
||||
std::string_view value, const std::unordered_map<std::string, std::unique_ptr<AnnotationData>> &annotation_id_map)
|
||||
{
|
||||
ASSERT(type_.has_value());
|
||||
|
||||
auto type = type_.value();
|
||||
|
||||
if (type == Value::Type::ARRAY) {
|
||||
ASSERT(component_type_.has_value());
|
||||
type = component_type_.value();
|
||||
}
|
||||
|
||||
auto res = CreateValue(type, value, annotation_id_map);
|
||||
if (!res) {
|
||||
return res.Error();
|
||||
}
|
||||
|
||||
values_.push_back(res.Value());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::Store(std::string_view attribute)
|
||||
{
|
||||
if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element isn't completely defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (IsParseAnnotation()) {
|
||||
ResetAnnotationBuilder();
|
||||
}
|
||||
|
||||
return Metadata::Store(attribute);
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::MeetExpRecordAttribute(std::string_view attribute,
|
||||
std::string_view value)
|
||||
{
|
||||
if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element isn't completely defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
InitializeAnnotationBuilder(value);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::MeetExpIdAttribute(std::string_view attribute,
|
||||
std::string_view value)
|
||||
{
|
||||
if (!IsParseAnnotation() || IsParseAnnotationElement()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation record attribute must be defined first",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (annotation_builder_.HasId()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation id attribute already defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
annotation_builder_.SetId(value);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::MeetExpElementNameAttribute(std::string_view attribute,
|
||||
std::string_view value)
|
||||
{
|
||||
if (!IsParseAnnotation()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation record attribute must be defined first",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Previous annotation element isn't defined completely",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
InitializeAnnotationElementBuilder(value);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::MeetExpElementTypeAttribute(std::string_view attribute,
|
||||
std::string_view value)
|
||||
{
|
||||
if (!IsParseAnnotationElement()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element name attribute must be defined first",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (annotation_element_builder_.IsTypeSet()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element type attribute already defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
annotation_element_builder_.SetType(GetType(value));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::MeetExpElementArrayComponentTypeAttribute(std::string_view attribute,
|
||||
std::string_view value)
|
||||
{
|
||||
if (!IsParseAnnotationElement()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element name attribute must be defined first",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (!annotation_element_builder_.IsArray()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) + "'. Annotation element type isn't array",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (annotation_element_builder_.IsComponentTypeSet()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element array component type attribute already defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
annotation_element_builder_.SetComponentType(GetType(value));
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::MeetExpElementValueAttribute(std::string_view attribute,
|
||||
std::string_view value)
|
||||
{
|
||||
if (!IsParseAnnotationElement()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element name attribute must be defined first",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (!annotation_element_builder_.IsTypeSet()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element type attribute isn't defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (annotation_element_builder_.IsArray() && !annotation_element_builder_.IsComponentTypeSet()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element array component type attribute isn't defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (!annotation_element_builder_.IsArray() && annotation_element_builder_.IsCompleted()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element is completely defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
return annotation_element_builder_.AddValue(value, id_map_);
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::StoreValue(std::string_view attribute, std::string_view value)
|
||||
{
|
||||
auto err = Metadata::StoreValue(attribute, value);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (IsAnnotationRecordAttribute(attribute)) {
|
||||
return MeetExpRecordAttribute(attribute, value);
|
||||
}
|
||||
|
||||
if (IsAnnotationIdAttribute(attribute)) {
|
||||
return MeetExpIdAttribute(attribute, value);
|
||||
}
|
||||
|
||||
if (IsAnnotationElementNameAttribute(attribute)) {
|
||||
return MeetExpElementNameAttribute(attribute, value);
|
||||
}
|
||||
|
||||
if (IsAnnotationElementTypeAttribute(attribute)) {
|
||||
return MeetExpElementTypeAttribute(attribute, value);
|
||||
}
|
||||
|
||||
if (IsAnnotationElementArrayComponentTypeAttribute(attribute)) {
|
||||
return MeetExpElementArrayComponentTypeAttribute(attribute, value);
|
||||
}
|
||||
|
||||
if (IsAnnotationElementValueAttribute(attribute)) {
|
||||
return MeetExpElementValueAttribute(attribute, value);
|
||||
}
|
||||
|
||||
if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) {
|
||||
return Error(std::string("Unexpected attribute '").append(attribute) +
|
||||
"'. Annotation element isn't completely defined",
|
||||
Error::Type::UNEXPECTED_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (IsParseAnnotation()) {
|
||||
ResetAnnotationBuilder();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> AnnotationMetadata::ValidateData()
|
||||
{
|
||||
if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) {
|
||||
return Error("Annotation element isn't completely defined", Error::Type::MISSING_ATTRIBUTE);
|
||||
}
|
||||
|
||||
if (IsParseAnnotation()) {
|
||||
ResetAnnotationBuilder();
|
||||
}
|
||||
|
||||
return Metadata::ValidateData();
|
||||
}
|
||||
|
||||
std::string RecordMetadata::GetBase() const
|
||||
{
|
||||
auto base = GetAttributeValue("extends");
|
||||
if (base) {
|
||||
return base.value();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
std::vector<std::string> RecordMetadata::GetInterfaces() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool RecordMetadata::IsAnnotation() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RecordMetadata::IsRuntimeAnnotation() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RecordMetadata::IsTypeAnnotation() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RecordMetadata::IsRuntimeTypeAnnotation() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FunctionMetadata::HasImplementation() const
|
||||
{
|
||||
return ((ACC_ABSTRACT & GetAccessFlags()) == 0) && ((ACC_NATIVE & GetAccessFlags()) == 0);
|
||||
}
|
||||
|
||||
bool FunctionMetadata::IsCtor() const
|
||||
{
|
||||
return GetAttribute("ctor");
|
||||
}
|
||||
|
||||
bool FunctionMetadata::IsCctor() const
|
||||
{
|
||||
return GetAttribute("cctor");
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error> FieldMetadata::StoreValue(std::string_view attribute, std::string_view value)
|
||||
{
|
||||
auto err = ItemMetadata::StoreValue(attribute, value);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
if (IsValueAttribute(attribute)) {
|
||||
Value::Type value_type;
|
||||
if (!field_type_.IsObject()) {
|
||||
value_type = GetType(field_type_.GetName());
|
||||
} else {
|
||||
value_type = Value::Type::STRING;
|
||||
}
|
||||
|
||||
auto res = CreateValue(value_type, value);
|
||||
if (!res) {
|
||||
return res.Error();
|
||||
}
|
||||
|
||||
value_ = res.Value();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
#include <meta_gen.h>
|
||||
|
||||
} // namespace panda::pandasm
|
596
static_core/assembler/meta.h
Normal file
596
static_core/assembler/meta.h
Normal file
@ -0,0 +1,596 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_ASSEMBLER_META_H_
|
||||
#define PANDA_ASSEMBLER_META_H_
|
||||
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "annotation.h"
|
||||
#include "modifiers.h"
|
||||
|
||||
#include "assembly-type.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
class Metadata {
|
||||
public:
|
||||
class Error {
|
||||
public:
|
||||
enum class Type {
|
||||
INVALID_VALUE,
|
||||
MISSING_ATTRIBUTE,
|
||||
MISSING_VALUE,
|
||||
MULTIPLE_ATTRIBUTE,
|
||||
UNEXPECTED_ATTRIBUTE,
|
||||
UNEXPECTED_VALUE,
|
||||
UNKNOWN_ATTRIBUTE
|
||||
};
|
||||
|
||||
Error(std::string msg, Type type) : msg_(std::move(msg)), type_(type) {}
|
||||
~Error() = default;
|
||||
DEFAULT_MOVE_SEMANTIC(Error);
|
||||
DEFAULT_COPY_SEMANTIC(Error);
|
||||
|
||||
std::string GetMessage() const
|
||||
{
|
||||
return msg_;
|
||||
}
|
||||
|
||||
Type GetType() const
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string msg_;
|
||||
Type type_;
|
||||
};
|
||||
|
||||
Metadata() = default;
|
||||
|
||||
virtual ~Metadata() = default;
|
||||
|
||||
std::optional<Error> SetAttribute(std::string_view attribute)
|
||||
{
|
||||
auto err = Validate(attribute);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
SetFlags(attribute);
|
||||
|
||||
return Store(attribute);
|
||||
}
|
||||
|
||||
void RemoveAttribute(const std::string &attribute)
|
||||
{
|
||||
RemoveFlags(attribute);
|
||||
|
||||
set_attributes_.erase(attribute);
|
||||
}
|
||||
|
||||
bool GetAttribute(const std::string &attribute) const
|
||||
{
|
||||
return set_attributes_.find(attribute) != set_attributes_.cend();
|
||||
}
|
||||
|
||||
std::optional<Error> SetAttributeValue(std::string_view attribute, std::string_view value)
|
||||
{
|
||||
auto err = Validate(attribute, value);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
SetFlags(attribute, value);
|
||||
|
||||
return StoreValue(attribute, value);
|
||||
}
|
||||
|
||||
std::vector<std::string> GetAttributeValues(const std::string &attribute) const
|
||||
{
|
||||
auto it = attributes_.find(attribute);
|
||||
if (it == attributes_.cend()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::optional<std::string> GetAttributeValue(const std::string &attribute) const
|
||||
{
|
||||
auto values = GetAttributeValues(attribute);
|
||||
|
||||
if (!values.empty()) {
|
||||
return values.front();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
const std::unordered_set<std::string> &GetBoolAttributes() const
|
||||
{
|
||||
return set_attributes_;
|
||||
}
|
||||
|
||||
const std::unordered_map<std::string, std::vector<std::string>> &GetAttributes() const
|
||||
{
|
||||
return attributes_;
|
||||
}
|
||||
|
||||
virtual std::optional<Error> ValidateData()
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
DEFAULT_COPY_SEMANTIC(Metadata);
|
||||
|
||||
DEFAULT_MOVE_SEMANTIC(Metadata);
|
||||
|
||||
protected:
|
||||
virtual std::optional<Error> Validate(std::string_view attribute) const = 0;
|
||||
|
||||
virtual std::optional<Error> Validate(std::string_view attribute, std::string_view value) const = 0;
|
||||
|
||||
virtual std::optional<Error> StoreValue(std::string_view attribute, std::string_view value)
|
||||
{
|
||||
std::string key(attribute);
|
||||
auto it = attributes_.find(key);
|
||||
if (it == attributes_.cend()) {
|
||||
std::tie(it, std::ignore) = attributes_.try_emplace(key);
|
||||
}
|
||||
|
||||
it->second.emplace_back(value);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
virtual std::optional<Error> Store(std::string_view attribute)
|
||||
{
|
||||
set_attributes_.emplace(attribute);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
virtual void SetFlags(std::string_view attribute) = 0;
|
||||
|
||||
virtual void SetFlags(std::string_view attribute, std::string_view value) = 0;
|
||||
|
||||
virtual void RemoveFlags(std::string_view attribute) = 0;
|
||||
|
||||
virtual void RemoveFlags(std::string_view attribute, std::string_view value) = 0;
|
||||
|
||||
bool HasAttribute(std::string_view attribute) const
|
||||
{
|
||||
std::string key(attribute);
|
||||
return GetAttribute(key) || GetAttributeValue(key);
|
||||
}
|
||||
|
||||
std::optional<Error> ValidateSize(std::string_view value) const;
|
||||
|
||||
private:
|
||||
std::unordered_set<std::string> set_attributes_;
|
||||
std::unordered_map<std::string, std::vector<std::string>> attributes_;
|
||||
};
|
||||
|
||||
class AnnotationMetadata : public Metadata {
|
||||
public:
|
||||
const std::vector<AnnotationData> &GetAnnotations() const
|
||||
{
|
||||
return annotations_;
|
||||
}
|
||||
|
||||
void SetAnnotations(std::vector<AnnotationData> &&annotations)
|
||||
{
|
||||
annotations_ = std::forward<std::vector<AnnotationData>>(annotations);
|
||||
}
|
||||
|
||||
void AddAnnotations(const std::vector<AnnotationData> &annotations)
|
||||
{
|
||||
annotations_.insert(annotations_.end(), annotations.begin(), annotations.end());
|
||||
}
|
||||
|
||||
std::optional<Error> ValidateData() override;
|
||||
|
||||
protected:
|
||||
std::optional<Error> Store(std::string_view attribute) override;
|
||||
|
||||
std::optional<Error> StoreValue(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
virtual bool IsAnnotationRecordAttribute([[maybe_unused]] std::string_view attribute) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsAnnotationIdAttribute([[maybe_unused]] std::string_view attribute) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsAnnotationElementTypeAttribute([[maybe_unused]] std::string_view attribute) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsAnnotationElementArrayComponentTypeAttribute([[maybe_unused]] std::string_view attribute) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsAnnotationElementNameAttribute([[maybe_unused]] std::string_view attribute) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool IsAnnotationElementValueAttribute([[maybe_unused]] std::string_view attribute) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
class AnnotationElementBuilder {
|
||||
public:
|
||||
void Initialize(std::string_view name)
|
||||
{
|
||||
name_ = name;
|
||||
is_initialized_ = true;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
name_.clear();
|
||||
values_.clear();
|
||||
type_ = {};
|
||||
component_type_ = {};
|
||||
is_initialized_ = false;
|
||||
}
|
||||
|
||||
void SetType(Value::Type type)
|
||||
{
|
||||
type_ = type;
|
||||
}
|
||||
|
||||
void SetComponentType(Value::Type type)
|
||||
{
|
||||
ASSERT(type != Value::Type::ARRAY);
|
||||
component_type_ = type;
|
||||
}
|
||||
|
||||
std::optional<Error> AddValue(
|
||||
std::string_view value,
|
||||
const std::unordered_map<std::string, std::unique_ptr<AnnotationData>> &annotation_id_map);
|
||||
|
||||
AnnotationElement CreateAnnotationElement()
|
||||
{
|
||||
if (IsArray()) {
|
||||
return AnnotationElement(name_,
|
||||
std::make_unique<ArrayValue>(component_type_.value(), std::move(values_)));
|
||||
}
|
||||
|
||||
return AnnotationElement(name_, std::make_unique<ScalarValue>(values_.front()));
|
||||
}
|
||||
|
||||
bool IsArray() const
|
||||
{
|
||||
return type_.value() == Value::Type::ARRAY;
|
||||
}
|
||||
|
||||
bool IsTypeSet() const
|
||||
{
|
||||
return type_.has_value();
|
||||
}
|
||||
|
||||
bool IsComponentTypeSet() const
|
||||
{
|
||||
return component_type_.has_value();
|
||||
}
|
||||
|
||||
bool IsInitialized() const
|
||||
{
|
||||
return is_initialized_;
|
||||
}
|
||||
|
||||
bool IsCompleted() const
|
||||
{
|
||||
if (!IsTypeSet()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsArray() && !IsComponentTypeSet()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!IsArray() && values_.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_initialized_ {false};
|
||||
std::string name_;
|
||||
std::optional<Value::Type> type_;
|
||||
std::optional<Value::Type> component_type_;
|
||||
std::vector<ScalarValue> values_;
|
||||
};
|
||||
|
||||
class AnnotationBuilder {
|
||||
public:
|
||||
void Initialize(std::string_view name)
|
||||
{
|
||||
name_ = name;
|
||||
is_initialized_ = true;
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
name_.clear();
|
||||
elements_.clear();
|
||||
id_ = {};
|
||||
is_initialized_ = false;
|
||||
}
|
||||
|
||||
void SetId(std::string_view id)
|
||||
{
|
||||
id_ = id;
|
||||
}
|
||||
|
||||
std::string GetId() const
|
||||
{
|
||||
ASSERT(HasId());
|
||||
return id_.value();
|
||||
}
|
||||
|
||||
void AddElement(AnnotationElement &&element)
|
||||
{
|
||||
elements_.push_back(std::forward<AnnotationElement>(element));
|
||||
}
|
||||
|
||||
std::unique_ptr<AnnotationData> CreateAnnotationData()
|
||||
{
|
||||
return std::make_unique<AnnotationData>(name_, std::move(elements_));
|
||||
};
|
||||
|
||||
void AddAnnnotationDataToVector(std::vector<AnnotationData> *annotations)
|
||||
{
|
||||
annotations->emplace_back(name_, std::move(elements_));
|
||||
}
|
||||
|
||||
bool HasId() const
|
||||
{
|
||||
return id_.has_value();
|
||||
}
|
||||
|
||||
bool IsInitialized() const
|
||||
{
|
||||
return is_initialized_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
std::optional<std::string> id_;
|
||||
std::vector<AnnotationElement> elements_;
|
||||
bool is_initialized_ {false};
|
||||
};
|
||||
|
||||
std::optional<Metadata::Error> MeetExpRecordAttribute(std::string_view attribute, std::string_view value);
|
||||
std::optional<Metadata::Error> MeetExpIdAttribute(std::string_view attribute, std::string_view value);
|
||||
std::optional<Metadata::Error> MeetExpElementNameAttribute(std::string_view attribute, std::string_view value);
|
||||
std::optional<Metadata::Error> MeetExpElementTypeAttribute(std::string_view attribute, std::string_view value);
|
||||
std::optional<Metadata::Error> MeetExpElementArrayComponentTypeAttribute(std::string_view attribute,
|
||||
std::string_view value);
|
||||
std::optional<Metadata::Error> MeetExpElementValueAttribute(std::string_view attribute, std::string_view value);
|
||||
|
||||
void InitializeAnnotationBuilder(std::string_view name)
|
||||
{
|
||||
if (IsParseAnnotation()) {
|
||||
ResetAnnotationBuilder();
|
||||
}
|
||||
|
||||
annotation_builder_.Initialize(name);
|
||||
}
|
||||
|
||||
void ResetAnnotationBuilder()
|
||||
{
|
||||
ASSERT(IsParseAnnotation());
|
||||
|
||||
if (IsParseAnnotationElement() && annotation_element_builder_.IsCompleted()) {
|
||||
ResetAnnotationElementBuilder();
|
||||
}
|
||||
|
||||
if (annotation_builder_.HasId()) {
|
||||
id_map_.insert({annotation_builder_.GetId(), annotation_builder_.CreateAnnotationData()});
|
||||
} else {
|
||||
annotation_builder_.AddAnnnotationDataToVector(&annotations_);
|
||||
}
|
||||
|
||||
annotation_builder_.Reset();
|
||||
}
|
||||
|
||||
bool IsParseAnnotation() const
|
||||
{
|
||||
return annotation_builder_.IsInitialized();
|
||||
}
|
||||
|
||||
void InitializeAnnotationElementBuilder(std::string_view name)
|
||||
{
|
||||
if (IsParseAnnotationElement() && annotation_element_builder_.IsCompleted()) {
|
||||
ResetAnnotationElementBuilder();
|
||||
}
|
||||
|
||||
annotation_element_builder_.Initialize(name);
|
||||
}
|
||||
|
||||
void ResetAnnotationElementBuilder()
|
||||
{
|
||||
ASSERT(IsParseAnnotationElement());
|
||||
ASSERT(annotation_element_builder_.IsCompleted());
|
||||
|
||||
annotation_builder_.AddElement(annotation_element_builder_.CreateAnnotationElement());
|
||||
|
||||
annotation_element_builder_.Reset();
|
||||
}
|
||||
|
||||
bool IsParseAnnotationElement() const
|
||||
{
|
||||
return annotation_element_builder_.IsInitialized();
|
||||
}
|
||||
|
||||
AnnotationBuilder annotation_builder_;
|
||||
AnnotationElementBuilder annotation_element_builder_;
|
||||
std::vector<AnnotationData> annotations_;
|
||||
std::unordered_map<std::string, std::unique_ptr<AnnotationData>> id_map_;
|
||||
};
|
||||
|
||||
class ItemMetadata : public AnnotationMetadata {
|
||||
public:
|
||||
uint32_t GetAccessFlags() const
|
||||
{
|
||||
return access_flags_;
|
||||
}
|
||||
|
||||
void SetAccessFlags(uint32_t access_flags)
|
||||
{
|
||||
access_flags_ = access_flags;
|
||||
}
|
||||
|
||||
PANDA_PUBLIC_API bool IsForeign() const;
|
||||
|
||||
private:
|
||||
uint32_t access_flags_ {0};
|
||||
};
|
||||
|
||||
class RecordMetadata : public ItemMetadata {
|
||||
public:
|
||||
virtual std::string GetBase() const;
|
||||
|
||||
virtual std::vector<std::string> GetInterfaces() const;
|
||||
|
||||
virtual bool IsAnnotation() const;
|
||||
|
||||
virtual bool IsRuntimeAnnotation() const;
|
||||
|
||||
virtual bool IsTypeAnnotation() const;
|
||||
|
||||
virtual bool IsRuntimeTypeAnnotation() const;
|
||||
|
||||
protected:
|
||||
std::optional<Error> Validate(std::string_view attribute) const override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute, std::string_view value) const override;
|
||||
|
||||
void SetFlags(std::string_view attribute) override;
|
||||
|
||||
void SetFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute, std::string_view value) override;
|
||||
};
|
||||
|
||||
class FieldMetadata : public ItemMetadata {
|
||||
public:
|
||||
void SetFieldType(const Type &type)
|
||||
{
|
||||
field_type_ = type;
|
||||
}
|
||||
|
||||
Type GetFieldType() const
|
||||
{
|
||||
return field_type_;
|
||||
}
|
||||
|
||||
void SetValue(const ScalarValue &value)
|
||||
{
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
std::optional<ScalarValue> GetValue() const
|
||||
{
|
||||
return value_;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::optional<Error> StoreValue(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute) const override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute, std::string_view value) const override;
|
||||
|
||||
void SetFlags(std::string_view attribute) override;
|
||||
|
||||
void SetFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
virtual bool IsValueAttribute(std::string_view attribute)
|
||||
{
|
||||
return attribute == "value";
|
||||
}
|
||||
|
||||
private:
|
||||
Type field_type_;
|
||||
std::optional<ScalarValue> value_;
|
||||
};
|
||||
|
||||
class FunctionMetadata : public ItemMetadata {
|
||||
public:
|
||||
virtual bool HasImplementation() const;
|
||||
|
||||
virtual bool IsCtor() const;
|
||||
|
||||
virtual bool IsCctor() const;
|
||||
|
||||
protected:
|
||||
std::optional<Error> Validate(std::string_view attribute) const override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute, std::string_view value) const override;
|
||||
|
||||
void SetFlags(std::string_view attribute) override;
|
||||
|
||||
void SetFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute, std::string_view value) override;
|
||||
};
|
||||
|
||||
class ParamMetadata : public AnnotationMetadata {
|
||||
protected:
|
||||
std::optional<Error> Validate(std::string_view attribute) const override;
|
||||
|
||||
std::optional<Error> Validate(std::string_view attribute, std::string_view value) const override;
|
||||
|
||||
void SetFlags(std::string_view attribute) override;
|
||||
|
||||
void SetFlags(std::string_view attribute, std::string_view value) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute) override;
|
||||
|
||||
void RemoveFlags(std::string_view attribute, std::string_view value) override;
|
||||
};
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_ASSEMBLER_META_H_
|
115
static_core/assembler/metadata.yaml
Normal file
115
static_core/assembler/metadata.yaml
Normal file
@ -0,0 +1,115 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
attributes:
|
||||
- name: access.field
|
||||
type: enum
|
||||
multiple: false
|
||||
values:
|
||||
- value: public
|
||||
flags: [ACC_PUBLIC]
|
||||
- value: protected
|
||||
flags: [ACC_PROTECTED]
|
||||
- value: private
|
||||
flags: [ACC_PRIVATE]
|
||||
applicable_to:
|
||||
- field
|
||||
|
||||
- name: access.function
|
||||
type: enum
|
||||
multiple: false
|
||||
values:
|
||||
- value: public
|
||||
flags: [ACC_PUBLIC]
|
||||
- value: protected
|
||||
flags: [ACC_PROTECTED]
|
||||
- value: private
|
||||
flags: [ACC_PRIVATE]
|
||||
applicable_to:
|
||||
- function
|
||||
|
||||
- name: access.record
|
||||
type: enum
|
||||
multiple: false
|
||||
values:
|
||||
- value: public
|
||||
flags: [ACC_PUBLIC]
|
||||
- value: protected
|
||||
flags: [ACC_PROTECTED]
|
||||
- value: private
|
||||
flags: [ACC_PRIVATE]
|
||||
applicable_to:
|
||||
- record
|
||||
|
||||
- name: extends
|
||||
type: record
|
||||
multiple: false
|
||||
applicable_to:
|
||||
- record
|
||||
|
||||
- name: external
|
||||
type: bool
|
||||
applicable_to:
|
||||
- record
|
||||
- field
|
||||
- function
|
||||
|
||||
- name: native
|
||||
type: bool
|
||||
flags: [ACC_NATIVE]
|
||||
applicable_to:
|
||||
- function
|
||||
|
||||
- name: noimpl
|
||||
type: bool
|
||||
flags: [ACC_ABSTRACT]
|
||||
applicable_to:
|
||||
- function
|
||||
|
||||
- name: static
|
||||
type: bool
|
||||
flags: [ACC_STATIC]
|
||||
applicable_to:
|
||||
- field
|
||||
- function
|
||||
|
||||
- name: final
|
||||
type: bool
|
||||
flags: [ACC_FINAL]
|
||||
applicable_to:
|
||||
- record
|
||||
- field
|
||||
- function
|
||||
|
||||
- name: volatile
|
||||
type: bool
|
||||
flags: [ACC_VOLATILE]
|
||||
multiple: false
|
||||
applicable_to:
|
||||
- field
|
||||
|
||||
- name: ctor
|
||||
type: bool
|
||||
applicable_to:
|
||||
- function
|
||||
|
||||
- name: cctor
|
||||
type: bool
|
||||
applicable_to:
|
||||
- function
|
||||
|
||||
- name: value
|
||||
type: any
|
||||
multiple: false
|
||||
applicable_to:
|
||||
- field
|
289
static_core/assembler/pandasm.cpp
Normal file
289
static_core/assembler/pandasm.cpp
Normal file
@ -0,0 +1,289 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ark_version.h"
|
||||
|
||||
#include "assembly-emitter.h"
|
||||
#include "assembly-parser.h"
|
||||
#ifdef PANDA_WITH_BYTECODE_OPTIMIZER
|
||||
#include "bytecode_optimizer/optimize_bytecode.h"
|
||||
#endif
|
||||
#include "file_format_version.h"
|
||||
#include "error.h"
|
||||
#include "lexer.h"
|
||||
#include "pandasm.h"
|
||||
#include "utils/expected.h"
|
||||
#include "utils/logger.h"
|
||||
#include "utils/pandargs.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
void PrintError(const panda::pandasm::Error &e, const std::string &msg)
|
||||
{
|
||||
std::stringstream sos;
|
||||
std::cerr << msg << ": " << e.message << std::endl;
|
||||
sos << " Line " << e.line_number << ", Column " << e.pos + 1 << ": ";
|
||||
std::cerr << sos.str() << e.whole_line << std::endl;
|
||||
std::cerr << std::setw(static_cast<int>(e.pos + sos.str().size()) + 1) << "^" << std::endl;
|
||||
}
|
||||
|
||||
void PrintErrors(const panda::pandasm::ErrorList &warnings, const std::string &msg)
|
||||
{
|
||||
for (const auto &iter : warnings) {
|
||||
PrintError(iter, msg);
|
||||
}
|
||||
}
|
||||
|
||||
void PrintHelp(const panda::PandArgParser &pa_parser)
|
||||
{
|
||||
std::cerr << "Usage:" << std::endl;
|
||||
std::cerr << "pandasm [OPTIONS] INPUT_FILE OUTPUT_FILE" << std::endl << std::endl;
|
||||
std::cerr << "Supported options:" << std::endl << std::endl;
|
||||
std::cerr << pa_parser.GetHelpString() << std::endl;
|
||||
}
|
||||
|
||||
bool PrepareArgs(panda::PandArgParser &pa_parser, const panda::PandArg<std::string> &input_file,
|
||||
const panda::PandArg<std::string> &output_file, const panda::PandArg<std::string> &log_file,
|
||||
const panda::PandArg<bool> &help, const panda::PandArg<bool> &verbose,
|
||||
const panda::PandArg<bool> &version, std::ifstream &inputfile, int argc, const char **argv)
|
||||
{
|
||||
if (!pa_parser.Parse(argc, argv)) {
|
||||
PrintHelp(pa_parser);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (version.GetValue()) {
|
||||
panda::PrintPandaVersion();
|
||||
panda_file::PrintBytecodeVersion();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input_file.GetValue().empty() || output_file.GetValue().empty() || help.GetValue()) {
|
||||
PrintHelp(pa_parser);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (verbose.GetValue()) {
|
||||
if (log_file.GetValue().empty()) {
|
||||
panda::Logger::ComponentMask component_mask;
|
||||
component_mask.set(panda::Logger::Component::ASSEMBLER);
|
||||
component_mask.set(panda::Logger::Component::BYTECODE_OPTIMIZER);
|
||||
panda::Logger::InitializeStdLogging(panda::Logger::Level::DEBUG, component_mask);
|
||||
} else {
|
||||
panda::Logger::ComponentMask component_mask;
|
||||
component_mask.set(panda::Logger::Component::ASSEMBLER);
|
||||
component_mask.set(panda::Logger::Component::BYTECODE_OPTIMIZER);
|
||||
panda::Logger::InitializeFileLogging(log_file.GetValue(), panda::Logger::Level::DEBUG, component_mask);
|
||||
}
|
||||
}
|
||||
|
||||
inputfile.open(input_file.GetValue(), std::ifstream::in);
|
||||
|
||||
if (!inputfile) {
|
||||
std::cerr << "The input file does not exist." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Tokenize(panda::pandasm::Lexer &lexer, std::vector<std::vector<panda::pandasm::Token>> &tokens,
|
||||
std::ifstream &inputfile)
|
||||
{
|
||||
std::string s;
|
||||
|
||||
while (getline(inputfile, s)) {
|
||||
panda::pandasm::Tokens q = lexer.TokenizeString(s);
|
||||
|
||||
auto e = q.second;
|
||||
|
||||
if (e.err != panda::pandasm::Error::ErrorType::ERR_NONE) {
|
||||
e.line_number = tokens.size() + 1;
|
||||
PrintError(e, "ERROR");
|
||||
return false;
|
||||
}
|
||||
|
||||
tokens.push_back(q.first);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseProgram(panda::pandasm::Parser &parser, std::vector<std::vector<panda::pandasm::Token>> &tokens,
|
||||
const panda::PandArg<std::string> &input_file,
|
||||
panda::Expected<panda::pandasm::Program, panda::pandasm::Error> &res)
|
||||
{
|
||||
res = parser.Parse(tokens, input_file.GetValue());
|
||||
|
||||
if (!res) {
|
||||
PrintError(res.Error(), "ERROR");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DumpProgramInJson(panda::pandasm::Program &program, const panda::PandArg<std::string> &scopes_file)
|
||||
{
|
||||
if (!scopes_file.GetValue().empty()) {
|
||||
std::ofstream dump_file;
|
||||
dump_file.open(scopes_file.GetValue());
|
||||
|
||||
if (!dump_file) {
|
||||
std::cerr << "Cannot write scopes into the given file." << std::endl;
|
||||
return false;
|
||||
}
|
||||
dump_file << program.JsonDump();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmitProgramInBinary(panda::pandasm::Program &program, panda::PandArgParser &pa_parser,
|
||||
const panda::PandArg<std::string> &output_file, panda::PandArg<bool> &optimize,
|
||||
panda::PandArg<bool> &size_stat)
|
||||
{
|
||||
auto emit_debug_info = !optimize.GetValue();
|
||||
std::map<std::string, size_t> stat;
|
||||
std::map<std::string, size_t> *statp = size_stat.GetValue() ? &stat : nullptr;
|
||||
panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
|
||||
panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = optimize.GetValue() ? &maps : nullptr;
|
||||
|
||||
if (!panda::pandasm::AsmEmitter::Emit(output_file.GetValue(), program, statp, mapsp, emit_debug_info)) {
|
||||
std::cerr << "Failed to emit binary data: " << panda::pandasm::AsmEmitter::GetLastError() << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef PANDA_WITH_BYTECODE_OPTIMIZER
|
||||
if (optimize.GetValue()) {
|
||||
bool is_optimized = panda::bytecodeopt::OptimizeBytecode(&program, mapsp, output_file.GetValue());
|
||||
if (!panda::pandasm::AsmEmitter::Emit(output_file.GetValue(), program, statp, mapsp, emit_debug_info)) {
|
||||
std::cerr << "Failed to emit binary data: " << panda::pandasm::AsmEmitter::GetLastError() << std::endl;
|
||||
return false;
|
||||
}
|
||||
if (!is_optimized) {
|
||||
std::cerr << "Bytecode optimizer reported internal errors" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (size_stat.GetValue()) {
|
||||
size_t total_size = 0;
|
||||
std::cout << "Panda file size statistic:" << std::endl;
|
||||
|
||||
for (auto [name, size] : stat) {
|
||||
std::cout << name << " section: " << size << std::endl;
|
||||
total_size += size;
|
||||
}
|
||||
|
||||
std::cout << "total: " << total_size << std::endl;
|
||||
}
|
||||
|
||||
pa_parser.DisableTail();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BuildFiles(panda::pandasm::Program &program, panda::PandArgParser &pa_parser,
|
||||
const panda::PandArg<std::string> &output_file, panda::PandArg<bool> &optimize,
|
||||
panda::PandArg<bool> &size_stat, panda::PandArg<std::string> &scopes_file)
|
||||
{
|
||||
if (!DumpProgramInJson(program, scopes_file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!EmitProgramInBinary(program, pa_parser, output_file, optimize, size_stat)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
panda::PandArg<bool> verbose("verbose", false, "Enable verbose output (will be printed to standard output)");
|
||||
panda::PandArg<std::string> log_file("log-file", "", "(--log-file FILENAME) Set log file name");
|
||||
panda::PandArg<std::string> scopes_file("dump-scopes", "",
|
||||
"(--dump-scopes FILENAME) Enable dump of scopes to file");
|
||||
panda::PandArg<bool> help("help", false, "Print this message and exit");
|
||||
panda::PandArg<bool> size_stat("size-stat", false, "Print panda file size statistic");
|
||||
panda::PandArg<bool> optimize("optimize", false, "Run the bytecode optimization");
|
||||
panda::PandArg<bool> version {"version", false,
|
||||
"Ark version, file format version and minimum supported file format version"};
|
||||
// tail arguments
|
||||
panda::PandArg<std::string> input_file("INPUT_FILE", "", "Path to the source assembly code");
|
||||
panda::PandArg<std::string> output_file("OUTPUT_FILE", "", "Path to the generated binary code");
|
||||
panda::PandArgParser pa_parser;
|
||||
pa_parser.Add(&verbose);
|
||||
pa_parser.Add(&help);
|
||||
pa_parser.Add(&log_file);
|
||||
pa_parser.Add(&scopes_file);
|
||||
pa_parser.Add(&size_stat);
|
||||
pa_parser.Add(&optimize);
|
||||
pa_parser.Add(&version);
|
||||
pa_parser.PushBackTail(&input_file);
|
||||
pa_parser.PushBackTail(&output_file);
|
||||
pa_parser.EnableTail();
|
||||
|
||||
std::ifstream inputfile;
|
||||
|
||||
if (!panda::pandasm::PrepareArgs(pa_parser, input_file, output_file, log_file, help, verbose, version, inputfile,
|
||||
argc, argv)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "Lexical analysis:";
|
||||
|
||||
panda::pandasm::Lexer lexer;
|
||||
|
||||
std::vector<std::vector<panda::pandasm::Token>> tokens;
|
||||
|
||||
if (!Tokenize(lexer, tokens, inputfile)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
LOG(DEBUG, ASSEMBLER) << "parsing:";
|
||||
|
||||
panda::pandasm::Parser parser;
|
||||
|
||||
panda::Expected<panda::pandasm::Program, panda::pandasm::Error> res;
|
||||
if (!panda::pandasm::ParseProgram(parser, tokens, input_file, res)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
auto &program = res.Value();
|
||||
|
||||
auto w = parser.ShowWarnings();
|
||||
if (!w.empty()) {
|
||||
panda::pandasm::PrintErrors(w, "WARNING");
|
||||
}
|
||||
|
||||
if (!panda::pandasm::BuildFiles(program, pa_parser, output_file, optimize, size_stat, scopes_file)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
51
static_core/assembler/pandasm.h
Normal file
51
static_core/assembler/pandasm.h
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_PANDASM_H
|
||||
#define PANDA_PANDASM_H
|
||||
|
||||
#include "utils/pandargs.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
void PrintError(const panda::pandasm::Error &e, const std::string &msg);
|
||||
|
||||
void PrintErrors(const panda::pandasm::ErrorList &warnings, const std::string &msg);
|
||||
|
||||
bool PrepareArgs(panda::PandArgParser &pa_parser, const panda::PandArg<std::string> &input_file,
|
||||
const panda::PandArg<std::string> &output_file, const panda::PandArg<std::string> &log_file,
|
||||
const panda::PandArg<bool> &help, const panda::PandArg<bool> &verbose, std::ifstream &inputfile,
|
||||
int argc, char **argv);
|
||||
|
||||
bool Tokenize(panda::pandasm::Lexer &lexer, std::vector<std::vector<panda::pandasm::Token>> &tokens,
|
||||
std::ifstream &inputfile);
|
||||
|
||||
bool ParseProgram(panda::pandasm::Parser &parser, std::vector<std::vector<panda::pandasm::Token>> &tokens,
|
||||
const panda::PandArg<std::string> &input_file,
|
||||
panda::Expected<panda::pandasm::Program, panda::pandasm::Error> &res);
|
||||
|
||||
bool DumpProgramInJson(panda::pandasm::Program &program, const panda::PandArg<std::string> &scopes_file);
|
||||
|
||||
bool EmitProgramInBinary(panda::pandasm::Program &program, panda::PandArgParser &pa_parser,
|
||||
const panda::PandArg<std::string> &output_file, panda::PandArg<bool> &optimize,
|
||||
panda::PandArg<bool> &size_stat);
|
||||
|
||||
bool BuildFiles(panda::pandasm::Program &program, panda::PandArgParser &pa_parser,
|
||||
const panda::PandArg<std::string> &output_file, panda::PandArg<bool> &optimize,
|
||||
panda::PandArg<bool> &size_stat, panda::PandArg<std::string> &scopes_file);
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // PANDA_PANDASM_H
|
83
static_core/assembler/samples/Bubblesort.pa
Normal file
83
static_core/assembler/samples/Bubblesort.pa
Normal file
@ -0,0 +1,83 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
.function i64 main(){
|
||||
ldai 30000
|
||||
sta v1
|
||||
newarr v1, i64[]
|
||||
sta.obj v0
|
||||
call.short init, v0, v1
|
||||
call.short bubblesort, v0, v0
|
||||
lda v1
|
||||
subi 1
|
||||
ldarr.64 v0
|
||||
return.64
|
||||
}
|
||||
|
||||
.function void init(i64[] a0, i32 a1){
|
||||
movi v2, 0
|
||||
loop:
|
||||
lda a1
|
||||
jeqz init_exit
|
||||
subi 1
|
||||
sta a1
|
||||
starr.64 a0, v2
|
||||
inci v2, 1
|
||||
lda v2
|
||||
jmp loop
|
||||
init_exit:
|
||||
return.void
|
||||
}
|
||||
|
||||
.function void bubblesort(i64[] a0){
|
||||
lenarr a0
|
||||
sta v1
|
||||
outer:
|
||||
ldai 1
|
||||
sta v2
|
||||
ldai 1
|
||||
inner:
|
||||
jge v1, inner_exit
|
||||
sta v3
|
||||
ldarr.64 a0
|
||||
sta v4
|
||||
lda v3
|
||||
subi 1
|
||||
sta v5
|
||||
ldarr.64 a0
|
||||
jlt v4, next
|
||||
call swap, a0, v5, v3, v0
|
||||
movi v2, 0
|
||||
next:
|
||||
lda v3
|
||||
addi 1
|
||||
jmp inner
|
||||
inner_exit:
|
||||
inci v1, -1
|
||||
lda v2
|
||||
jeqz outer
|
||||
return.void
|
||||
}
|
||||
|
||||
.function void swap(i64[] a0, i32 a1, i32 a2){
|
||||
lda a1
|
||||
ldarr.64 a0
|
||||
sta v3
|
||||
lda a2
|
||||
ldarr.64 a0
|
||||
starr.64 a0, a1
|
||||
lda v3
|
||||
starr.64 a0, a2
|
||||
return.void
|
||||
}
|
37
static_core/assembler/samples/Factorial.pa
Normal file
37
static_core/assembler/samples/Factorial.pa
Normal file
@ -0,0 +1,37 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
.function i32 factorial (i32 a0) <> { #Calculation of factorial from a value in register a0
|
||||
ldai.64 1
|
||||
sta.64 v8
|
||||
while_1:
|
||||
lda.64 a0
|
||||
movi.64 v0, 1
|
||||
jle v0, endwhile_3
|
||||
body_2:
|
||||
mul v8, a0
|
||||
sta.64 v8
|
||||
lda.64 a0
|
||||
subi 1
|
||||
sta.64 a0
|
||||
jmp while_1
|
||||
endwhile_3:
|
||||
lda.64 v8
|
||||
return
|
||||
}
|
||||
|
||||
.function i32 entry () <> {
|
||||
movi.64 v0, 7
|
||||
call.short factorial, v0
|
||||
return
|
||||
}
|
52
static_core/assembler/samples/Fibonacci.pa
Normal file
52
static_core/assembler/samples/Fibonacci.pa
Normal file
@ -0,0 +1,52 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
.function i64 main(){
|
||||
movi v1, 10
|
||||
newarr v0, v1, i64[]
|
||||
ldai 0
|
||||
main_loop:
|
||||
jge v1, main_ret
|
||||
sta v2
|
||||
call.short fibonacci, v2, v2
|
||||
starr.64 v0, v2
|
||||
lda v2
|
||||
addi 1
|
||||
jmp main_loop
|
||||
main_ret:
|
||||
lda v1
|
||||
subi 1
|
||||
ldarr.64 v0
|
||||
return.64
|
||||
}
|
||||
|
||||
.function i64 fibonacci(i64 a0){
|
||||
lda a0
|
||||
jnez non_zero
|
||||
return.64
|
||||
non_zero:
|
||||
ldai 1
|
||||
jne a0, non_one
|
||||
return.64
|
||||
non_one:
|
||||
lda a0
|
||||
subi 1
|
||||
sta a0
|
||||
subi 1
|
||||
sta v1
|
||||
call.short fibonacci, a0, a0
|
||||
sta a0
|
||||
call.short fibonacci, v1, a0
|
||||
add2.64 a0
|
||||
return.64
|
||||
}
|
62
static_core/assembler/templates/ins_create_api.h.erb
Normal file
62
static_core/assembler/templates/ins_create_api.h.erb
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Autogenerated file -- DO NOT EDIT!
|
||||
|
||||
#include <initializer_list>
|
||||
#include "assembly-ins.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
|
||||
% insn = group.first
|
||||
% signature = assembler_signature(group, insn.jump?)
|
||||
% signature_str = signature.map { |o| "#{o.type} #{o.name}" }.join(', ')
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
inline Ins Create_<%= insn.asm_token %>(<%= signature_str %>)
|
||||
{
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
Ins <%=insn.emitter_name%>_;
|
||||
<%=group.first.emitter_name%>_.opcode = Opcode::<%= insn.asm_token %>;
|
||||
% format = format_ops(insn.format).select { |o| o.name != 'prof' }
|
||||
% format.each { |o| o.width = storage_width(o.width) }
|
||||
% count_reg = 0
|
||||
% format.each_with_index do |o, i|
|
||||
% if o.name.start_with?('v')
|
||||
% count_reg += 1
|
||||
% end
|
||||
% end
|
||||
% if count_reg > 0 then
|
||||
<%=group.first.emitter_name%>_.regs.reserve(<%= count_reg %>);
|
||||
% end
|
||||
% format.each_with_index do |o, i|
|
||||
% if o.name.start_with?('imm')
|
||||
% if insn.jump?
|
||||
<%=group.first.emitter_name%>_.ids.push_back(label);
|
||||
% else
|
||||
<%=group.first.emitter_name%>_.imms.emplace_back(<%= o.name %>);
|
||||
% end
|
||||
% elsif o.name.start_with?('id')
|
||||
<%=group.first.emitter_name%>_.ids.push_back(<%= o.name %>);
|
||||
% else
|
||||
<%=group.first.emitter_name%>_.regs.push_back(<%= o.name %>);
|
||||
% end
|
||||
% end
|
||||
return <%=insn.emitter_name%>_;
|
||||
}
|
||||
|
||||
% end
|
||||
|
||||
} // namespace panda::pandasm
|
186
static_core/assembler/templates/ins_emit.h.erb
Normal file
186
static_core/assembler/templates/ins_emit.h.erb
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "assembly-ins.h"
|
||||
#include "mangling.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
// NOLINTBEGIN(readability-container-size-empty)
|
||||
|
||||
// NOLINTNEXTLINE(misc-definitions-in-headers,readability-function-size)
|
||||
bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method,
|
||||
const std::unordered_map<std::string, panda_file::BaseMethodItem *> &methods,
|
||||
const std::unordered_map<std::string, panda_file::BaseFieldItem *> &fields,
|
||||
const std::unordered_map<std::string, panda_file::BaseClassItem *> &classes,
|
||||
const std::unordered_map<std::string_view, panda_file::StringItem *> &strings,
|
||||
const std::unordered_map<std::string, panda_file::LiteralArrayItem *> &literalarrays,
|
||||
const std::unordered_map<std::string_view, panda::Label>& labels) const {
|
||||
if (!IsValidToEmit()) {
|
||||
std::cerr << "Invalid instruction: " << ToString() << std::endl;
|
||||
LOG(FATAL, ASSEMBLER);
|
||||
}
|
||||
switch(opcode) {
|
||||
% instruction_hash = Panda::instructions.map { |i| [i.mnemonic, i] }.to_h
|
||||
%
|
||||
% Panda::instructions.group_by(&:mnemonic).each_pair do |mn, group|
|
||||
% insn = group[index_of_max(group.map(&:format).map(&:size))]
|
||||
%
|
||||
% def type(insn)
|
||||
% src_acc_ops = insn.acc_and_operands.select(&:src?)
|
||||
% src_acc_ops.size != 0 ? src_acc_ops.first.type : 'none'
|
||||
% end
|
||||
%
|
||||
% def op_size(insn)
|
||||
% type(insn)[1..-1].to_i
|
||||
% end
|
||||
%
|
||||
% def operands(insn, regs = "regs")
|
||||
% ops = []
|
||||
% nr = 0
|
||||
% ni = 0
|
||||
% insn.operands.each do |op|
|
||||
% if op.reg?
|
||||
% ops << "#{regs}[#{nr}]"
|
||||
% nr += 1
|
||||
% elsif op.imm?
|
||||
% if insn.jump?
|
||||
% ops << 'labels.find(ids[0])->second'
|
||||
% else
|
||||
% from_type, to_type = op_size(insn) == 64 ? ['double', 'int64_t'] : ['float', 'int32_t']
|
||||
% if insn.float?
|
||||
% ops << bit_cast("imms[#{ni}]", to_type, from_type)
|
||||
% elsif type(insn).start_with? 'u' # can hold both float and integer literals
|
||||
% ops << "std::holds_alternative<double>(imms[#{ni}]) ? #{bit_cast("imms[#{ni}]", to_type, from_type)} : std::get<int64_t>(imms[#{ni}])"
|
||||
% else
|
||||
% ops << "std::get<int64_t>(imms[#{ni}])"
|
||||
% end
|
||||
% end
|
||||
% ni += 1
|
||||
% elsif op.id?
|
||||
% if insn.properties.include?('method_id')
|
||||
% ops << 'methods.find(ids[0])->second->GetIndex(method)'
|
||||
% elsif insn.properties.include?('field_id')
|
||||
% ops << 'fields.find(ids[0])->second->GetIndex(method)'
|
||||
% elsif insn.properties.include?('type_id')
|
||||
% ops << 'classes.find(ids[0])->second->GetIndex(method)'
|
||||
% elsif insn.properties.include?('string_id')
|
||||
% ops << 'strings.find(ids[0])->second->GetOffset()'
|
||||
% elsif insn.properties.include?('literalarray_id')
|
||||
% ops << 'static_cast<uint32_t>(literalarrays.find(ids[0])->second->GetIndex())'
|
||||
% else
|
||||
% raise "Unexpected ID type"
|
||||
% end
|
||||
% else
|
||||
% raise "Unexpected operand type"
|
||||
% end
|
||||
% end
|
||||
% ops << "profile_id" if insn.profiled?
|
||||
% if insn.properties.include?('short_long_range')
|
||||
% ops << ops.shift
|
||||
% end
|
||||
% ops
|
||||
% end
|
||||
case Opcode::<%= insn.asm_token %>: {
|
||||
% if insn.properties.include?('method_id')
|
||||
if (ids.empty() || (methods.find(ids[0]) == methods.cend())) {
|
||||
return false;
|
||||
}
|
||||
% elsif insn.properties.include?('field_id')
|
||||
if (ids.empty() || (fields.find(ids[0]) == fields.cend())) {
|
||||
return false;
|
||||
}
|
||||
% elsif insn.properties.include?('type_id')
|
||||
if (ids.empty() || (classes.find(ids[0]) == classes.cend())) {
|
||||
return false;
|
||||
}
|
||||
% elsif insn.properties.include?('string_id')
|
||||
if (ids.empty() || (strings.find(ids[0]) == strings.cend())) {
|
||||
return false;
|
||||
}
|
||||
% elsif insn.jump?
|
||||
if (ids.empty() || (labels.find(ids[0]) == labels.cend())) {
|
||||
return false;
|
||||
}
|
||||
% end
|
||||
% regs_num = 0
|
||||
% imms_num = 0
|
||||
% insn.operands.each do |op|
|
||||
% if op.reg?
|
||||
% regs_num += 1
|
||||
% elsif op.imm?
|
||||
% imms_num += 1
|
||||
% end
|
||||
% end
|
||||
% if insn.properties.include?('short_long_range') && !insn.range?
|
||||
% if imms_num > 0
|
||||
if (imms.size() < <%= imms_num %>) {
|
||||
return false;
|
||||
}
|
||||
% end
|
||||
% elsif insn.jump?
|
||||
% if regs_num > 0
|
||||
if (regs.size() < <%= regs_num %>) {
|
||||
return false;
|
||||
}
|
||||
% end
|
||||
% else
|
||||
% if regs_num > 0 and imms_num > 0
|
||||
if (regs.size() < <%= regs_num %> || imms.size() < <%= imms_num %>) {
|
||||
return false;
|
||||
}
|
||||
% elsif regs_num > 0
|
||||
if (regs.size() < <%= regs_num %>) {
|
||||
return false;
|
||||
}
|
||||
% elsif imms_num > 0
|
||||
if (imms.size() < <%= imms_num %>) {
|
||||
return false;
|
||||
}
|
||||
% end
|
||||
% end
|
||||
% if insn.properties.include?('short_long_range') && !insn.mnemonic.include?('range')
|
||||
auto registers = regs;
|
||||
% call_mnemonics = if insn.mnemonic.end_with?('.short')
|
||||
% [insn.mnemonic]
|
||||
% else
|
||||
% ["#{insn.mnemonic}.short", insn.mnemonic]
|
||||
% end
|
||||
% call_mnemonics.map { |m| instruction_hash[m] }.each do |i|
|
||||
% registers = i.operands.select(&:reg?)
|
||||
if (registers.size() < <%= registers.size + 1 %>) {
|
||||
while (registers.size() < <%= registers.size %>) {
|
||||
registers.push_back(0);
|
||||
}
|
||||
emitter.<%= i.emitter_name %>(<%= operands(i, "registers").join(", ") %>);
|
||||
break;
|
||||
}
|
||||
% end
|
||||
% else
|
||||
emitter.<%= insn.emitter_name %>(<%= operands(insn).join(", ") %>);
|
||||
% end
|
||||
break;
|
||||
}
|
||||
% end
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// NOLINTEND(readability-container-size-empty)
|
||||
|
||||
} // namespace panda::pandasm
|
77
static_core/assembler/templates/ins_to_string.cpp.erb
Normal file
77
static_core/assembler/templates/ins_to_string.cpp.erb
Normal file
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include "assembly-ins.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
// NOLINTNEXTLINE(readability-function-size)
|
||||
std::string panda::pandasm::Ins::ToString(const std::string &endline, bool print_args /* = false */,
|
||||
size_t first_arg_idx /* = 0*/) const {
|
||||
std::string full_operation {};
|
||||
std::string reg_case {};
|
||||
if (this->set_label) {
|
||||
full_operation += this->label +": ";
|
||||
}
|
||||
switch(this->opcode) {
|
||||
|
||||
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
|
||||
% insn = group.first
|
||||
% formats = group.map(&:format)
|
||||
% sig_split = insn["sig"].split(' ')
|
||||
% operands = insn.operands
|
||||
% properties = insn.properties
|
||||
case panda::pandasm::Opcode::<%= insn.asm_token%>: {
|
||||
full_operation += "<%= insn.mnemonic%>";
|
||||
% idx_imm = 0
|
||||
% idx_reg = 0
|
||||
% idx_ids = 0
|
||||
% sig_split.length.times do |index|
|
||||
% item = sig_split[index]
|
||||
% next if index == 0
|
||||
% #TODO(knazarov): refactor next line
|
||||
% if (item.include?("id") || item.start_with?("imm") && insn.jump?)
|
||||
full_operation += IdToString(<%= idx_ids%>, <%= index == 1 ? "true" : "false"%>);
|
||||
% idx_ids += 1
|
||||
% elsif item.start_with?("imm")
|
||||
full_operation += ImmToString(<%= idx_imm%>, <%= index == 1 ? "true" : "false"%>);
|
||||
% idx_imm += 1
|
||||
% elsif item.start_with?("v")
|
||||
full_operation += RegToString(<%= idx_reg%>, <%= index == 1 ? "true" : "false"%>, print_args, first_arg_idx);
|
||||
% idx_reg += 1
|
||||
% end
|
||||
% end
|
||||
% if insn.profiled?
|
||||
full_operation += " # [prof=";
|
||||
full_operation += std::to_string(profile_id);
|
||||
full_operation += ']';
|
||||
% end
|
||||
} break;
|
||||
% end
|
||||
% Panda::pseudo_instructions.each do |insn|
|
||||
case panda::pandasm::Opcode::<%= insn.opcode %>: {
|
||||
full_operation += "<%= insn.opcode %>";
|
||||
full_operation += this->OperandsToString(print_args, first_arg_idx);
|
||||
} break;
|
||||
% end
|
||||
case panda::pandasm::Opcode::INVALID: {
|
||||
full_operation += "";
|
||||
} break;
|
||||
}
|
||||
return full_operation + endline;
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
60
static_core/assembler/templates/isa.h.erb
Normal file
60
static_core/assembler/templates/isa.h.erb
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
|
||||
#define PANDA_INSTRUCTION_LIST(_) \
|
||||
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
|
||||
% insn = group.first
|
||||
% formats = group.map(&:format)
|
||||
% pretty_format = insn.format.pretty.upcase.gsub(/[0-9]/, '')
|
||||
% pretty_format.gsub!('IMM', 'ID') if insn.jump?
|
||||
% pretty_format.gsub!('ID', 'TYPE') if insn.properties.include?('type_id')
|
||||
%
|
||||
% flags = ["InstFlags::NONE"]
|
||||
% flags << "InstFlags::CALL" if insn.simple_call?
|
||||
% flags << "InstFlags::JUMP" if insn.jump?
|
||||
% flags << "InstFlags::COND" if insn.conditional?
|
||||
% flags << "InstFlags::RETURN" if insn.return?
|
||||
% flags << "InstFlags::ACC_READ" if insn.acc_read?
|
||||
% flags << "InstFlags::ACC_WRITE" if insn.acc_write?
|
||||
% flags << "InstFlags::THROWING" if insn.throwing?
|
||||
% flags << "InstFlags::METHOD_ID" if insn.properties.include? 'method_id'
|
||||
% flags << "InstFlags::FIELD_ID" if insn.properties.include? 'field_id'
|
||||
% flags << "InstFlags::TYPE_ID" if insn.properties.include? 'type_id'
|
||||
% flags << "InstFlags::STRING_ID" if insn.properties.include? 'string_id'
|
||||
% flags << "InstFlags::LITERALARRAY_ID" if insn.properties.include? 'literalarray_id'
|
||||
% flags << "InstFlags::CALL_RANGE" if (insn.properties.include?('call') || insn.stripped_mnemonic == 'initobj') && insn.range?
|
||||
% flags = "(#{flags.join(" | ")})"
|
||||
%
|
||||
% max_width = group.map do |i|
|
||||
% i.operands.select(&:reg?).map(&:width).max
|
||||
% end.max
|
||||
% max_width ||= 0
|
||||
%
|
||||
% profile_size = insn.profiled? ? Panda::profiles[insn.profile.name].size : 0
|
||||
%
|
||||
% regs = insn.operands.select(&:reg?)
|
||||
% dst_idx = regs.index(&:dst?) || 'INVALID_REG_IDX'
|
||||
% use_idxs = regs.size.times.select { |idx| regs[idx].src? } || []
|
||||
% use_idxs += (['INVALID_REG_IDX'] * (max_number_of_src_regs - use_idxs.size))
|
||||
% use_idxs = "(std::array<int, #{ max_number_of_src_regs }>{{#{use_idxs.join(', ')}}})"
|
||||
%
|
||||
_(<%= insn.asm_token %>, "<%= insn.mnemonic %>", <%= pretty_format %>, <%= max_width %>, <%= flags %>, <%= dst_idx %>, <%= use_idxs %>, <%= profile_size %>) \
|
||||
% end
|
||||
% Panda::pseudo_instructions.each do |insn|
|
||||
% use_idxs = insn.use_idxs + ['INVALID_REG_IDX'] * (max_number_of_src_regs - insn.use_idxs.size)
|
||||
% use_idxs = "(std::array<int, #{max_number_of_src_regs}>{{#{use_idxs.join(', ')}}})"
|
||||
_(<%= insn.opcode %> , "<%= insn.opcode %>", NONE, 0, (<%= insn.flags.join(" | ") %>), <%= insn.dst_idx %>, <%= use_idxs %>, 0) \
|
||||
% end
|
||||
|
50
static_core/assembler/templates/meta_gen.cpp.erb
Normal file
50
static_core/assembler/templates/meta_gen.cpp.erb
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// NOLINTBEGIN(readability-function-size, misc-definitions-in-headers)
|
||||
|
||||
% Metadata::item_types.each do |item_type|
|
||||
std::optional<Metadata::Error>
|
||||
<%= MetadataGen::class_name(item_type) %>::Validate(<%= MetadataGen::validate_arg_list(item_type, true).join(', ') %>) const {
|
||||
<%= MetadataGen::validate_body(item_type, true).join("\n") %>
|
||||
}
|
||||
|
||||
std::optional<Metadata::Error>
|
||||
<%= MetadataGen::class_name(item_type) %>::Validate(<%= MetadataGen::validate_arg_list(item_type, false).join(', ') %>) const {
|
||||
<%= MetadataGen::validate_body(item_type, false).join("\n") %>
|
||||
}
|
||||
|
||||
% end
|
||||
%
|
||||
% Metadata::item_types.each do |item_type|
|
||||
void <%= MetadataGen::class_name(item_type) %>::SetFlags(<%= MetadataGen::flags_arg_list(item_type, true).join(', ') %>) {
|
||||
<%= MetadataGen::set_flags_body(item_type, true).join("\n") %>
|
||||
}
|
||||
|
||||
void <%= MetadataGen::class_name(item_type) %>::SetFlags(<%= MetadataGen::flags_arg_list(item_type, false).join(', ') %>) {
|
||||
<%= MetadataGen::set_flags_body(item_type, false).join("\n") %>
|
||||
}
|
||||
|
||||
void <%= MetadataGen::class_name(item_type) %>::RemoveFlags(<%= MetadataGen::flags_arg_list(item_type, true).join(', ') %>) {
|
||||
<%= MetadataGen::remove_flags_body(item_type, true).join("\n") %>
|
||||
}
|
||||
|
||||
void <%= MetadataGen::class_name(item_type) %>::RemoveFlags(<%= MetadataGen::flags_arg_list(item_type, false).join(', ') %>) {
|
||||
<%= MetadataGen::remove_flags_body(item_type, false).join("\n") %>
|
||||
}
|
||||
|
||||
% end
|
||||
|
||||
// NOLINTEND(readability-function-size, misc-definitions-in-headers)
|
143
static_core/assembler/templates/opcode_parsing.h.erb
Normal file
143
static_core/assembler/templates/opcode_parsing.h.erb
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "assembly-parser.h"
|
||||
#include "utils/number-utils.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
// NOLINTNEXTLINE(misc-definitions-in-headers,readability-function-size)
|
||||
bool Parser::ParseOperands()
|
||||
{
|
||||
std::string_view p;
|
||||
uint64_t number;
|
||||
LOG(DEBUG, ASSEMBLER) << "operand search started (line " << line_stric_ << "): " << context_.tokens[0].whole_line;
|
||||
switch(context_.WaitFor())
|
||||
{
|
||||
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
|
||||
% insn = group.first
|
||||
% formats = group.map(&:format)
|
||||
% operands = insn.operands
|
||||
% properties = insn.properties
|
||||
% verification = insn.verification
|
||||
case Token::Type::ID_OP_<%= insn.asm_token%>: {
|
||||
% if insn.return? && !insn.properties.include?('dynamic')
|
||||
% if insn.return_obj?
|
||||
if (!curr_func_->return_type.IsObject()) {
|
||||
% elsif insn.return32?
|
||||
if (!curr_func_->return_type.IsPrim32()) {
|
||||
% elsif insn.return64?
|
||||
if (!curr_func_->return_type.IsPrim64()) {
|
||||
% elsif insn.return_void?
|
||||
if (!curr_func_->return_type.IsVoid()) {
|
||||
% end
|
||||
GetWarning("Unexpected return type. Look at the return type in the function definition: " +
|
||||
curr_func_->return_type.GetName(),
|
||||
Error::ErrorType::WAR_UNEXPECTED_RETURN_TYPE);
|
||||
}
|
||||
% end
|
||||
% required_args = operands.size
|
||||
% required_args = 1 if insn.call?
|
||||
% required_args = 2 if insn.stripped_mnemonic == 'calli'
|
||||
% operands.each_with_index do |op, j|
|
||||
%
|
||||
% if (j != 0)
|
||||
% if j >= required_args
|
||||
if (!context_.Mask()) {
|
||||
ParseOperandComma();
|
||||
}
|
||||
% else
|
||||
if (!context_.Mask()) {
|
||||
ParseOperandComma();
|
||||
} else {
|
||||
context_.err = GetError("Expected comma.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS);
|
||||
}
|
||||
% end
|
||||
% end
|
||||
%
|
||||
if (!context_.Mask()) {
|
||||
% if op.reg?
|
||||
|
||||
if (RegValidName()) {
|
||||
p = context_.GiveToken();
|
||||
p.remove_prefix(1);
|
||||
number = ToNumber(p);
|
||||
size_t reg_width = curr_func_->ins.back().MaxRegEncodingWidth();
|
||||
if ((1ULL << reg_width) <= number) {
|
||||
context_.err = GetError("Register width mismatch.", Error::ErrorType::ERR_BAD_OPERAND);
|
||||
}
|
||||
} else if (context_.err.err == Error::ErrorType::ERR_NONE) {
|
||||
context_.err = GetError("Invalid name of register.", Error::ErrorType::ERR_BAD_NAME_REG);
|
||||
}
|
||||
|
||||
ParseOperandVreg();
|
||||
% elsif op.imm?
|
||||
% if properties.include?("jump")
|
||||
ParseOperandLabel();
|
||||
% else
|
||||
% if properties.include?("float")
|
||||
ParseOperandFloat(<%= op.size == 64 ? "true" : "false" %>);
|
||||
% else
|
||||
ParseOperandInteger();
|
||||
% end
|
||||
% end
|
||||
% elsif op.id?
|
||||
% if properties.include?("type_id")
|
||||
% if (verification.include?("type_id_array"))
|
||||
ParseOperandType(Type::VerificationType::TYPE_ID_ARRAY);
|
||||
% elsif (verification.include?("type_id_object"))
|
||||
ParseOperandType(Type::VerificationType::TYPE_ID_OBJECT);
|
||||
% elsif (verification.include?("type_id_class"))
|
||||
ParseOperandType(Type::VerificationType::TYPE_ID_CLASS);
|
||||
% elsif (verification.include?("type_id_any_object"))
|
||||
ParseOperandType(Type::VerificationType::TYPE_ID_ANY_OBJECT);
|
||||
% end
|
||||
% elsif properties.include?("string_id")
|
||||
ParseOperandString();
|
||||
% elsif properties.include?("method_id")
|
||||
% if insn.opcode[0..6] == "initobj"
|
||||
ParseOperandInitobj();
|
||||
% else
|
||||
ParseOperandCall();
|
||||
% end
|
||||
% elsif properties.include?("literalarray_id") # NOTE:
|
||||
% # this check must stay below check for
|
||||
% # properties.include?("method_id"), because we have opcodes
|
||||
% # with multiple id's, and their parsing is order-sensitive
|
||||
ParseOperandLiteralArray();
|
||||
% elsif properties.include?("field_id")
|
||||
ParseOperandField();
|
||||
% else
|
||||
ParseOperandId();
|
||||
% end
|
||||
% end
|
||||
%
|
||||
% if (j >= required_args) && (operands.size > 0)
|
||||
}
|
||||
% elsif operands.size > 0
|
||||
} else {
|
||||
context_.err = GetError("Expected more arguments.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS);
|
||||
}
|
||||
% end
|
||||
% end
|
||||
ParseOperandNone();
|
||||
} break;
|
||||
%end
|
||||
default:
|
||||
context_.err = GetError("No such operation.", Error::ErrorType::ERR_BAD_NONEXISTING_OPERATION);
|
||||
return false;
|
||||
}
|
||||
return context_.Mask();
|
||||
}
|
||||
} // namespace panda::pandasm
|
52
static_core/assembler/templates/operand_types_print.h.erb
Normal file
52
static_core/assembler/templates/operand_types_print.h.erb
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "assembly-parser.h"
|
||||
|
||||
namespace panda::pandasm {
|
||||
// NOLINTNEXTLINE(readability-function-size)
|
||||
inline std::string OperandTypePrint(panda::pandasm::Opcode op) {
|
||||
switch (op) {
|
||||
% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group|
|
||||
% insn = group.first
|
||||
% operands = insn.operands
|
||||
% properties = insn.properties
|
||||
case Opcode::<%= group.first.asm_token%>: {
|
||||
% operands_list = operands.map do |op|
|
||||
% if op.reg?
|
||||
% 'reg'
|
||||
% elsif op.imm?
|
||||
% properties.include?('jump') ? 'label' : 'imm'
|
||||
% elsif op.id?
|
||||
% if properties.include?('type_id')
|
||||
% 'type'
|
||||
% elsif properties.include?('string_id')
|
||||
% 'string'
|
||||
% elsif properties.include?('method_id')
|
||||
% 'call'
|
||||
% else
|
||||
% 'id'
|
||||
% end
|
||||
% end
|
||||
% end.join('_')
|
||||
% operands_list = 'none' if operands_list == ''
|
||||
return "<%= operands_list%>";
|
||||
};
|
||||
%end
|
||||
default:
|
||||
return "undefined";
|
||||
}
|
||||
}
|
||||
} // namespace panda::pandasm
|
1043
static_core/assembler/tests/emitter_test.cpp
Normal file
1043
static_core/assembler/tests/emitter_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
227
static_core/assembler/tests/lexer_test.cpp
Normal file
227
static_core/assembler/tests/lexer_test.cpp
Normal file
@ -0,0 +1,227 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "../define.h"
|
||||
#include "../lexer.h"
|
||||
|
||||
// NOLINTNEXTLINE(google-build-using-namespace)
|
||||
using namespace panda::pandasm;
|
||||
|
||||
TEST(lexertests, test1)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "mov v1, v2";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "DEL_COMMA") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[3].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test2)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "ldai 1";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test3)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "movi\nlda v2 v10 mov v2";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[3].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[4].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[5].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test4)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "jmp Iasdfsadkfjhasifhsaiuhdacoisjdaociewhasdasdfkjasdfhjksadhfkhsakdfjhksajhdkfjhskhdfkjahhjdskaj";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test5)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "call.short 1111, 1";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "DEL_COMMA") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[3].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test6)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "jle v1 met";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test7)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "label:";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test8)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = ",";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "DEL_COMMA") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test9)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = ",:{}()<>=";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "DEL_COMMA") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "DEL_COLON") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "DEL_BRACE_L") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[3].type), "DEL_BRACE_R") << "DEL_COMMA expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[4].type), "DEL_BRACKET_L") << "DEL_BRACKET_L expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[5].type), "DEL_BRACKET_R") << "DEL_BRACKET_R expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[6].type), "DEL_LT") << "DEL_LT expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[7].type), "DEL_GT") << "DEL_GT expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[8].type), "DEL_EQ") << "DEL_EQ expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test11)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s =
|
||||
"i64.to.f32 alsdhashdjskhfka "
|
||||
"shdkfhkasdhfkhsakdhfkshkfhskahlfkjsdfkjadskhfkshadkhfsdakhfksahdkfaksdfkhaskldhkfashdlfkjhasdkjfhklasjhdfklhsa"
|
||||
"fhska";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, test12)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = ".function asd(u32){}";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "KEYWORD") << "KEYWORD expected";
|
||||
ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected";
|
||||
ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected";
|
||||
}
|
||||
|
||||
TEST(lexertests, string_literal)
|
||||
{
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "\"123";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
|
||||
Error e = tok.second;
|
||||
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_STRING_MISSING_TERMINATING_CHARACTER);
|
||||
}
|
||||
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = R"("123\")";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
|
||||
Error e = tok.second;
|
||||
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_STRING_MISSING_TERMINATING_CHARACTER);
|
||||
}
|
||||
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = R"(" a b \ c d ")";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
|
||||
Error e = tok.second;
|
||||
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE);
|
||||
ASSERT_EQ(tok.first.size(), 1U);
|
||||
ASSERT_EQ(tok.first[0].type, Token::Type::ID_STRING);
|
||||
ASSERT_EQ(tok.first[0].bound_left, 0U);
|
||||
ASSERT_EQ(tok.first[0].bound_right, s.length());
|
||||
}
|
||||
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "\"abcd\"1234";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
|
||||
Error e = tok.second;
|
||||
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE);
|
||||
ASSERT_EQ(tok.first.size(), 2U);
|
||||
ASSERT_EQ(tok.first[0].type, Token::Type::ID_STRING);
|
||||
ASSERT_EQ(tok.first[0].bound_left, 0U);
|
||||
ASSERT_EQ(tok.first[0].bound_right, s.find('1'));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(lexertests, array_type)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "i32[]";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
|
||||
Error e = tok.second;
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE);
|
||||
ASSERT_EQ(tok.first.size(), 3U);
|
||||
ASSERT_EQ(tok.first[0].type, Token::Type::ID);
|
||||
ASSERT_EQ(tok.first[1].type, Token::Type::DEL_SQUARE_BRACKET_L);
|
||||
ASSERT_EQ(tok.first[2].type, Token::Type::DEL_SQUARE_BRACKET_R);
|
||||
}
|
||||
|
||||
TEST(lexertests, record_type)
|
||||
{
|
||||
Lexer l;
|
||||
std::string s = "FunctionalInterface-u16-i32-u16[]-u1-0";
|
||||
Tokens tok = l.TokenizeString(s);
|
||||
|
||||
Error e = tok.second;
|
||||
ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE);
|
||||
ASSERT_EQ(tok.first.size(), 1U);
|
||||
ASSERT_EQ(tok.first[0].type, Token::Type::ID);
|
||||
}
|
60
static_core/assembler/tests/mangling_tests.cpp
Normal file
60
static_core/assembler/tests/mangling_tests.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "mangling.h"
|
||||
#include "assembly-function.h"
|
||||
#include "extensions/extensions.h"
|
||||
|
||||
// NOLINTNEXTLINE(google-build-using-namespace)
|
||||
using namespace panda::pandasm;
|
||||
|
||||
TEST(ManglingTests, MangleFunctionName)
|
||||
{
|
||||
std::vector<Function::Parameter> params;
|
||||
panda::panda_file::SourceLang language {panda::panda_file::SourceLang::PANDA_ASSEMBLY};
|
||||
params.emplace_back(Type {"type1", 0}, language);
|
||||
params.emplace_back(Type {"type2", 0}, language);
|
||||
params.emplace_back(Type {"type3", 0}, language);
|
||||
|
||||
auto return_type = Type("type4", 0);
|
||||
|
||||
std::string name = "Asm.main";
|
||||
ASSERT_EQ(MangleFunctionName(name, params, return_type), "Asm.main:type1;type2;type3;type4;");
|
||||
}
|
||||
|
||||
TEST(ManglingTests, DeMangleFunctionName)
|
||||
{
|
||||
std::string name = "Asm.main:type1;type2;type3;type4;";
|
||||
ASSERT_EQ(DeMangleName(name), "Asm.main");
|
||||
}
|
||||
|
||||
TEST(ManglingTests, GetFunctionSignatureFromName)
|
||||
{
|
||||
std::vector<Function::Parameter> params;
|
||||
panda::panda_file::SourceLang language {panda::panda_file::SourceLang::PANDA_ASSEMBLY};
|
||||
params.emplace_back(Type {"type1", 0}, language);
|
||||
params.emplace_back(Type {"type2", 0}, language);
|
||||
params.emplace_back(Type {"type3", 0}, language);
|
||||
|
||||
std::string name = "Asm.main";
|
||||
ASSERT_EQ(GetFunctionSignatureFromName(name, params), "Asm.main:(type1,type2,type3)");
|
||||
}
|
||||
|
||||
TEST(ManglingTests, GetFunctionNameFromSignature)
|
||||
{
|
||||
std::string name = "Asm.main:(type1,type2,type3,type4)";
|
||||
ASSERT_EQ(GetFunctionNameFromSignature(name), "Asm.main");
|
||||
}
|
4591
static_core/assembler/tests/parser_test.cpp
Normal file
4591
static_core/assembler/tests/parser_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
194
static_core/assembler/utils/number-utils.h
Normal file
194
static_core/assembler/utils/number-utils.h
Normal file
@ -0,0 +1,194 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _PANDA_ASSEMBLER_NUMBERS_UTILS_H
|
||||
#define _PANDA_ASSEMBLER_NUMBERS_UTILS_H
|
||||
|
||||
namespace panda::pandasm {
|
||||
|
||||
constexpr size_t HEX_BASE = 16;
|
||||
|
||||
constexpr size_t DEC_BASE = 10;
|
||||
|
||||
constexpr size_t OCT_BASE = 8;
|
||||
|
||||
constexpr size_t BIN_BASE = 2;
|
||||
|
||||
constexpr size_t MAX_DWORD = 65536;
|
||||
|
||||
inline bool ValidateInteger(std::string_view p)
|
||||
{
|
||||
constexpr size_t GENERAL_SHIFT = 2;
|
||||
|
||||
std::string_view token = p;
|
||||
|
||||
if (token.back() == '-' || token.back() == '+' || token.back() == 'x' || token == ".") {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (token[0] == '-' || token[0] == '+') {
|
||||
token.remove_prefix(1);
|
||||
}
|
||||
|
||||
if (token[0] == '0' && token.size() > 1 && token.find('.') == std::string::npos) {
|
||||
if (token[1] == 'x') {
|
||||
token.remove_prefix(GENERAL_SHIFT);
|
||||
|
||||
for (auto i : token) {
|
||||
if (!((i >= '0' && i <= '9') || (i >= 'A' && i <= 'F') || (i >= 'a' && i <= 'f'))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (token[1] == 'b') {
|
||||
token.remove_prefix(GENERAL_SHIFT);
|
||||
if (token.empty()) {
|
||||
return false;
|
||||
}
|
||||
for (auto i : token) {
|
||||
if (!(i == '0' || i == '1')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (token[1] >= '0' && token[1] <= '9' && token.find('e') == std::string::npos) {
|
||||
token.remove_prefix(1);
|
||||
|
||||
for (auto i : token) {
|
||||
if (!(i >= '0' && i <= '7')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto i : token) {
|
||||
if (!(i >= '0' && i <= '9')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline int64_t IntegerNumber(std::string_view p)
|
||||
{
|
||||
constexpr size_t GENERAL_SHIFT = 2;
|
||||
|
||||
// expects a valid number
|
||||
if (p.size() == 1) {
|
||||
return p[0] - '0';
|
||||
}
|
||||
|
||||
size_t minus_shift = 0;
|
||||
if (p[0] == '-') {
|
||||
minus_shift++;
|
||||
}
|
||||
|
||||
if (p[minus_shift + 1] == 'b') {
|
||||
p.remove_prefix(GENERAL_SHIFT + minus_shift);
|
||||
return std::strtoull(p.data(), nullptr, BIN_BASE) * (minus_shift == 0 ? 1 : -1);
|
||||
}
|
||||
|
||||
if (p[minus_shift + 1] == 'x') {
|
||||
return std::strtoull(p.data(), nullptr, HEX_BASE);
|
||||
}
|
||||
|
||||
if (p[minus_shift] == '0') {
|
||||
return std::strtoull(p.data(), nullptr, OCT_BASE);
|
||||
}
|
||||
|
||||
return std::strtoull(p.data(), nullptr, DEC_BASE);
|
||||
}
|
||||
|
||||
inline bool ValidateFloat(std::string_view p)
|
||||
{
|
||||
std::string_view token = p;
|
||||
|
||||
if (ValidateInteger(token)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (token[0] == '-' || token[0] == '+') {
|
||||
token.remove_prefix(1);
|
||||
}
|
||||
|
||||
bool dot = false;
|
||||
bool exp = false;
|
||||
bool nowexp = false;
|
||||
|
||||
for (auto i : token) {
|
||||
if (nowexp && (i == '-' || i == '+')) {
|
||||
nowexp = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nowexp) {
|
||||
nowexp = false;
|
||||
}
|
||||
|
||||
if (i == '.' && !exp && !dot) {
|
||||
dot = true;
|
||||
} else if (!exp && i == 'e') {
|
||||
nowexp = true;
|
||||
exp = true;
|
||||
} else if (!(i >= '0' && i <= '9')) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return !nowexp;
|
||||
}
|
||||
|
||||
inline double FloatNumber(std::string_view p, bool is_64bit)
|
||||
{
|
||||
constexpr size_t GENERAL_SHIFT = 2;
|
||||
// expects a valid number
|
||||
if (p.size() > GENERAL_SHIFT && p.substr(0, GENERAL_SHIFT) == "0x") { // hex literal
|
||||
char *end = nullptr;
|
||||
if (is_64bit) {
|
||||
return bit_cast<double>(strtoull(p.data(), &end, 0));
|
||||
}
|
||||
return bit_cast<float>(static_cast<uint32_t>(strtoull(p.data(), &end, 0)));
|
||||
}
|
||||
return std::strtold(std::string(p.data(), p.length()).c_str(), nullptr);
|
||||
}
|
||||
|
||||
inline size_t ToNumber(std::string_view p)
|
||||
{
|
||||
size_t sum = 0;
|
||||
|
||||
for (char i : p) {
|
||||
if (isdigit(i) != 0) {
|
||||
sum = sum * DEC_BASE + static_cast<size_t>(i - '0');
|
||||
} else {
|
||||
return MAX_DWORD;
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
} // namespace panda::pandasm
|
||||
|
||||
#endif // !_PANDA_ASSEMBLER_NUMBERS_UTILS_H
|
148
static_core/bytecode_optimizer/BUILD.gn
Normal file
148
static_core/bytecode_optimizer/BUILD.gn
Normal file
@ -0,0 +1,148 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import("//arkcompiler/runtime_core/static_core/ark_config.gni")
|
||||
import("//build/ohos.gni")
|
||||
import("$ark_root/plugins/plugins.gni")
|
||||
|
||||
config("bytecodeopt_public_config") {
|
||||
include_dirs = [
|
||||
"$target_gen_dir",
|
||||
"$ark_root/bytecode_optimizer",
|
||||
]
|
||||
if (enable_bytecode_optimizer && plugin_enable_bytecode_optimizer) {
|
||||
defines = [ "ENABLE_BYTECODE_OPT" ]
|
||||
}
|
||||
}
|
||||
|
||||
libarkbytecodeopt_sources = [
|
||||
"$ark_root/bytecode_optimizer/bytecodeopt_peepholes.cpp",
|
||||
"$ark_root/bytecode_optimizer/canonicalization.cpp",
|
||||
"$ark_root/bytecode_optimizer/check_resolver.cpp",
|
||||
"$ark_root/bytecode_optimizer/codegen.cpp",
|
||||
"$ark_root/bytecode_optimizer/common.cpp",
|
||||
"$ark_root/bytecode_optimizer/const_array_resolver.cpp",
|
||||
"$ark_root/bytecode_optimizer/optimize_bytecode.cpp",
|
||||
"$ark_root/bytecode_optimizer/reg_acc_alloc.cpp",
|
||||
"$ark_root/bytecode_optimizer/reg_encoder.cpp",
|
||||
]
|
||||
libarkbytecodeopt_sources += plugin_libarkbytecodeopt_sources
|
||||
|
||||
libarkbytecodeopt_configs = [
|
||||
sdk_libc_secshared_config,
|
||||
"$ark_root:ark_config",
|
||||
":bytecodeopt_public_config",
|
||||
"$ark_root/compiler:arkcompiler_public_config",
|
||||
"$ark_root/libpandabase:arkbase_public_config",
|
||||
"$ark_root/libpandafile:arkfile_public_config",
|
||||
"$ark_root/assembler:arkassembler_public_config",
|
||||
"$ark_root/runtime:arkruntime_public_config",
|
||||
]
|
||||
|
||||
ohos_shared_library("libarktsbytecodeopt") {
|
||||
sources = libarkbytecodeopt_sources
|
||||
|
||||
configs = libarkbytecodeopt_configs
|
||||
|
||||
deps = [
|
||||
":bytecodeopt_options_gen_h",
|
||||
":codegen_visitors_inc",
|
||||
":isa_gen_arkbytecodeopt_check_width_cpp",
|
||||
":isa_gen_arkbytecodeopt_check_width_h",
|
||||
":isa_gen_arkbytecodeopt_insn_selection_cpp",
|
||||
":isa_gen_arkbytecodeopt_insn_selection_h",
|
||||
":reg_encoder_visitors_inc",
|
||||
":codegen_intrinsics_cpp",
|
||||
"$ark_root/assembler:libarktsassembler",
|
||||
"$ark_root/compiler:libarktscompiler",
|
||||
"$ark_root/libpandabase:libarktsbase",
|
||||
"$ark_root/libpandafile:libarktsfile",
|
||||
]
|
||||
|
||||
deps += plugin_bytecodeopt_deps
|
||||
|
||||
output_extension = "so"
|
||||
part_name = ark_part_name
|
||||
subsystem_name = "$ark_subsystem_name"
|
||||
}
|
||||
|
||||
ohos_static_library("libarktsbytecodeopt_frontend_static") {
|
||||
sources = libarkbytecodeopt_sources
|
||||
|
||||
configs = libarkbytecodeopt_configs
|
||||
|
||||
deps = [
|
||||
":bytecodeopt_options_gen_h",
|
||||
":codegen_visitors_inc",
|
||||
":isa_gen_arkbytecodeopt_check_width_cpp",
|
||||
":isa_gen_arkbytecodeopt_check_width_h",
|
||||
":isa_gen_arkbytecodeopt_insn_selection_cpp",
|
||||
":isa_gen_arkbytecodeopt_insn_selection_h",
|
||||
":reg_encoder_visitors_inc",
|
||||
":codegen_intrinsics_cpp",
|
||||
"$ark_root/assembler:libarktsassembler_frontend_static",
|
||||
"$ark_root/compiler:libarktscompiler_frontend_static",
|
||||
"$ark_root/libpandabase:libarktsbase_frontend_static",
|
||||
"$ark_root/libpandafile:libarktsfile_frontend_static",
|
||||
]
|
||||
|
||||
deps += plugin_bytecodeopt_deps
|
||||
part_name = ark_part_name
|
||||
subsystem_name = ark_subsystem_name
|
||||
}
|
||||
|
||||
ark_isa_gen("isa_gen_arkbytecodeopt") {
|
||||
template_files = [
|
||||
"insn_selection.h.erb",
|
||||
"insn_selection.cpp.erb",
|
||||
"check_width.cpp.erb",
|
||||
"check_width.h.erb",
|
||||
]
|
||||
sources = "templates"
|
||||
destination = "$target_gen_dir/generated"
|
||||
requires = [
|
||||
"bytecode_optimizer_isapi.rb",
|
||||
"$ark_root/assembler/asm_isapi.rb",
|
||||
]
|
||||
}
|
||||
|
||||
ark_gen_file("bytecodeopt_options_gen_h") {
|
||||
template_file = "../templates/options/options.h.erb"
|
||||
data_file = "options.yaml"
|
||||
requires = [ "../templates/common.rb" ]
|
||||
output_file = "$target_gen_dir/generated/bytecodeopt_options_gen.h"
|
||||
}
|
||||
|
||||
ark_gen_file("reg_encoder_visitors_inc") {
|
||||
extra_dependencies = [ "$ark_root:concat_plugins_yamls" ]
|
||||
template_file = "templates/reg_encoder_visitors.inc.erb"
|
||||
data_file = "$ark_plugin_options_yaml"
|
||||
requires = [ "$ark_root/templates/plugin_options.rb" ]
|
||||
output_file = "$target_gen_dir/generated/reg_encoder_visitors.inc"
|
||||
}
|
||||
|
||||
ark_gen_file("codegen_visitors_inc") {
|
||||
extra_dependencies = [ "$ark_root:concat_plugins_yamls" ]
|
||||
template_file = "templates/codegen_visitors.inc.erb"
|
||||
data_file = "$ark_plugin_options_yaml"
|
||||
requires = [ "$ark_root/templates/plugin_options.rb" ]
|
||||
output_file = "$target_gen_dir/generated/codegen_visitors.inc"
|
||||
}
|
||||
|
||||
ark_gen_file("codegen_intrinsics_cpp") {
|
||||
extra_dependencies = [ "$ark_root:concat_plugins_yamls" ]
|
||||
template_file = "templates/codegen_intrinsics.cpp.erb"
|
||||
data_file = "$ark_plugin_options_yaml"
|
||||
requires = [ "$ark_root/templates/plugin_options.rb" ]
|
||||
output_file = "$target_gen_dir/generated/codegen_intrinsics.cpp"
|
||||
}
|
119
static_core/bytecode_optimizer/CMakeLists.txt
Normal file
119
static_core/bytecode_optimizer/CMakeLists.txt
Normal file
@ -0,0 +1,119 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
cmake_minimum_required(VERSION 3.5.2 FATAL_ERROR)
|
||||
|
||||
project(bytecode_optimizer)
|
||||
|
||||
include(cmake/coverage.cmake)
|
||||
|
||||
set(BYTECODE_OPT_SOURCES
|
||||
canonicalization.cpp
|
||||
codegen.cpp
|
||||
bytecodeopt_peepholes.cpp
|
||||
optimize_bytecode.cpp
|
||||
reg_acc_alloc.cpp
|
||||
reg_encoder.cpp
|
||||
check_resolver.cpp
|
||||
common.cpp
|
||||
const_array_resolver.cpp
|
||||
)
|
||||
|
||||
set(SOURCES ${BYTECODE_OPT_SOURCES})
|
||||
set(GENERATED_DIR ${CMAKE_CURRENT_BINARY_DIR}/generated)
|
||||
file(MAKE_DIRECTORY "${GENERATED_DIR}")
|
||||
|
||||
panda_isa_gen(
|
||||
TEMPLATES
|
||||
"insn_selection.h.erb"
|
||||
"insn_selection.cpp.erb"
|
||||
"check_width.cpp.erb"
|
||||
"check_width.h.erb"
|
||||
REQUIRES
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/bytecode_optimizer_isapi.rb"
|
||||
"${PANDA_ROOT}/assembler/asm_isapi.rb"
|
||||
DESTINATION
|
||||
"${GENERATED_DIR}"
|
||||
)
|
||||
|
||||
panda_add_library(arkbytecodeopt_obj OBJECT ${SOURCES})
|
||||
add_dependencies(arkbytecodeopt_obj isa_gen_bytecode_optimizer)
|
||||
panda_gen_options(TARGET arkbytecodeopt_obj YAML_FILE options.yaml GENERATED_HEADER bytecodeopt_options_gen.h)
|
||||
|
||||
set_target_properties(arkbytecodeopt_obj PROPERTIES
|
||||
POSITION_INDEPENDENT_CODE ON
|
||||
CXX_VISIBILITY_PRESET hidden
|
||||
VISIBILITY_INLINES_HIDDEN ON
|
||||
)
|
||||
|
||||
panda_target_include_directories(arkbytecodeopt_obj
|
||||
PUBLIC ${PANDA_ROOT}
|
||||
PUBLIC ${CMAKE_CURRENT_BINARY_DIR}
|
||||
PUBLIC ${GENERATED_DIR}
|
||||
)
|
||||
|
||||
panda_target_link_libraries(arkbytecodeopt_obj arkcompiler arkassembler arkfile arkbase)
|
||||
|
||||
panda_add_library(arkbytecodeopt_static STATIC $<TARGET_OBJECTS:arkbytecodeopt_obj>)
|
||||
panda_target_link_libraries(arkbytecodeopt_static arkbytecodeopt_obj)
|
||||
|
||||
panda_add_library(arkbytecodeopt ${PANDA_DEFAULT_LIB_TYPE} $<TARGET_OBJECTS:arkbytecodeopt_obj>)
|
||||
panda_target_link_libraries(arkbytecodeopt arkbytecodeopt_obj)
|
||||
|
||||
set(PANDA_BYTECODE_OPT_TESTS_LIBRARIES arkbytecodeopt_static)
|
||||
if (NOT (PANDA_TARGET_MOBILE OR PANDA_TARGET_OHOS OR PANDA_ENABLE_FUZZBENCH))
|
||||
list(APPEND PANDA_BYTECODE_OPT_TESTS_LIBRARIES stdc++fs)
|
||||
endif()
|
||||
|
||||
set(BYTECODE_OPT_TEST_SOURCES
|
||||
tests/bitops_bitwise_and_test.cpp
|
||||
tests/bc_lowering_test.cpp
|
||||
tests/codegen_test.cpp
|
||||
tests/reg_acc_alloc_test.cpp
|
||||
tests/reg_encoder_test.cpp
|
||||
tests/runtime_adapter_test.cpp
|
||||
tests/const_array_resolver_test.cpp
|
||||
tests/bytecodeopt_peepholes_test.cpp
|
||||
tests/check_resolver_test.cpp
|
||||
tests/canonicalization_test.cpp
|
||||
tests/irbuilder_test.cpp
|
||||
)
|
||||
|
||||
panda_add_gtest(
|
||||
NAME bytecodeopt_unit_tests
|
||||
SOURCES
|
||||
${BYTECODE_OPT_TEST_SOURCES}
|
||||
INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${GENERATED_DIR}/..
|
||||
${GENERATED_DIR}/../panda_gen_options
|
||||
LIBRARIES
|
||||
${PANDA_BYTECODE_OPT_TESTS_LIBRARIES}
|
||||
SANITIZERS
|
||||
${PANDA_SANITIZERS_LIST}
|
||||
)
|
||||
|
||||
panda_add_gtest(
|
||||
NO_CORES
|
||||
NAME bytecodeopt_peepholes_runtime_tests
|
||||
SOURCES
|
||||
tests/bytecodeopt_peepholes_runtime_test.cpp
|
||||
LIBRARIES
|
||||
arkassembler
|
||||
arkbytecodeopt
|
||||
arkruntime
|
||||
SANITIZERS
|
||||
${PANDA_SANITIZERS_LIST}
|
||||
)
|
||||
|
||||
panda_add_sanitizers(TARGET arkbytecodeopt SANITIZERS ${PANDA_SANITIZERS_LIST})
|
71
static_core/bytecode_optimizer/bytecode_encoder.h
Normal file
71
static_core/bytecode_optimizer/bytecode_encoder.h
Normal file
@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_BYTECODE_OPTIMIZER_BYTECODE_ENCODER_H
|
||||
#define PANDA_BYTECODE_OPTIMIZER_BYTECODE_ENCODER_H
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "compiler/optimizer/code_generator/encode.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
class BytecodeEncoder final : public compiler::Encoder {
|
||||
public:
|
||||
explicit BytecodeEncoder(ArenaAllocator *allocator) : Encoder(allocator, Arch::NONE) {}
|
||||
|
||||
void Finalize() override {};
|
||||
|
||||
static bool CanEncodeImmHelper(int64_t imm, uint32_t size, int64_t min, int64_t max)
|
||||
{
|
||||
constexpr uint8_t HALF_SIZE = 32;
|
||||
if (size != HALF_SIZE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return imm >= min && imm <= max;
|
||||
}
|
||||
|
||||
bool CanEncodeImmAddSubCmp(int64_t imm, uint32_t size, [[maybe_unused]] bool signed_compare) override
|
||||
{
|
||||
return CanEncodeImmHelper(imm, size, INT8_MIN, INT8_MAX);
|
||||
}
|
||||
|
||||
bool CanEncodeImmMulDivMod(uint64_t imm, uint32_t size) override
|
||||
{
|
||||
return CanEncodeImmAddSubCmp(imm, size, false);
|
||||
}
|
||||
|
||||
bool CanEncodeImmLogical(uint64_t imm, uint32_t size) override
|
||||
{
|
||||
return CanEncodeImmHelper(imm, size, INT32_MIN, INT32_MAX);
|
||||
}
|
||||
|
||||
bool CanEncodeShift(uint32_t size) override
|
||||
{
|
||||
constexpr uint32_t UNSUPPORTED_SHIFT_SIZE = 64;
|
||||
return size != UNSUPPORTED_SHIFT_SIZE;
|
||||
}
|
||||
size_t GetLabelAddress(compiler::LabelHolder::LabelId /* label */) override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
bool LabelHasLinks(compiler::LabelHolder::LabelId /* label */) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}; // BytecodeEncoder
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // PANDA_BYTECODE_OPTIMIZER_BYTECODE_ENCODER_H
|
565
static_core/bytecode_optimizer/bytecode_optimizer_isapi.rb
Executable file
565
static_core/bytecode_optimizer/bytecode_optimizer_isapi.rb
Executable file
@ -0,0 +1,565 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# ISAPI specialization for bytecode optimizer
|
||||
|
||||
Instruction.class_eval do
|
||||
def src_acc_kind
|
||||
op = acc_and_operands.select { |op| op.acc? && op.src? }.first
|
||||
raise "There is no src acc for #{mnemonic}" unless op
|
||||
data_kind_helper(op)
|
||||
end
|
||||
|
||||
def dst_acc_kind
|
||||
op = acc_and_operands.select { |op| op.acc? && op.dst? }.first
|
||||
raise "There is no dst acc for #{mnemonic}" unless op
|
||||
data_kind_helper(op)
|
||||
end
|
||||
|
||||
private
|
||||
# return one of 32, 64, 'ref'
|
||||
def data_kind_helper(op)
|
||||
m = /[fiub](?<size>\d+)/.match(op.type)
|
||||
if m
|
||||
size = m[:size].to_i
|
||||
if size == 64
|
||||
return 64
|
||||
else
|
||||
return 32
|
||||
end
|
||||
end
|
||||
return 'ref' if op.type == 'ref'
|
||||
raise "Unexpected operand type #{op.type} in data_kind_helper"
|
||||
end
|
||||
end
|
||||
|
||||
def instruction_hash
|
||||
unless defined? @instruction_hash
|
||||
@instruction_hash = Hash.new { |_, key| raise "No instruction with '#{key}' mnemonic" }
|
||||
Panda.instructions.each { |insn| @instruction_hash[insn.mnemonic] = insn }
|
||||
end
|
||||
@instruction_hash
|
||||
end
|
||||
|
||||
# Classes for bytecode description
|
||||
Visitor = Struct.new(:ir_op, :cpp, :switch)
|
||||
Switch = Struct.new(:expr, :cases) do
|
||||
def encode
|
||||
res = "switch (#{expr}) {\n"
|
||||
cases.each do |c|
|
||||
res << c.encode
|
||||
end
|
||||
res << "default:
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER) << \"Codegen for \" << compiler::GetOpcodeString(inst->GetOpcode()) << \" failed\";
|
||||
enc->success_ = false;
|
||||
}"
|
||||
res
|
||||
end
|
||||
|
||||
def check_width
|
||||
res = "switch (#{expr}) {\n"
|
||||
cases.each do |c|
|
||||
res << c.check_width
|
||||
end
|
||||
res << "default:
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER) << \"CheckWidth for \" << compiler::GetOpcodeString(inst->GetOpcode()) << \" failed\";
|
||||
re->success_ = false;
|
||||
}"
|
||||
res
|
||||
end
|
||||
end
|
||||
|
||||
Case = Struct.new(:types, :node) do
|
||||
def proxy(method)
|
||||
res = types.map { |type| "case #{type}:" }.join("\n")
|
||||
res << " {\n"
|
||||
res << node.send(method)
|
||||
res << "break;\n}\n"
|
||||
res
|
||||
end
|
||||
|
||||
def encode
|
||||
proxy(:encode)
|
||||
end
|
||||
|
||||
def check_width
|
||||
proxy(:check_width)
|
||||
end
|
||||
end
|
||||
|
||||
Leaf = Struct.new(:instruction, :args) do
|
||||
def encode
|
||||
res = ""
|
||||
args_str = args.join(",\n")
|
||||
if instruction.acc_read?
|
||||
res << do_lda(instruction)
|
||||
res << "\n"
|
||||
end
|
||||
res << "enc->result_.emplace_back(pandasm::Create_#{instruction.asm_token}(\n"
|
||||
res << args_str
|
||||
res << "\n));\n"
|
||||
if instruction.acc_write?
|
||||
res << do_sta(instruction)
|
||||
res << "\n"
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def check_width
|
||||
reg = instruction.operands.select(&:reg?).first
|
||||
if reg
|
||||
"re->Check#{reg.width}Width(inst);\n"
|
||||
else
|
||||
"return;\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
If = Struct.new(:condition, :true_expr, :false_expr) do
|
||||
def proxy(method)
|
||||
res = "if (#{condition}) {\n"
|
||||
res << true_expr.send(method)
|
||||
res << "} else {\n"
|
||||
res << false_expr.send(method)
|
||||
res << "}\n"
|
||||
res
|
||||
end
|
||||
|
||||
def encode
|
||||
proxy(:encode)
|
||||
end
|
||||
|
||||
def check_width
|
||||
proxy(:check_width)
|
||||
end
|
||||
end
|
||||
|
||||
Empty = Struct.new(:dummy) do
|
||||
def encode; end
|
||||
def check_width; end
|
||||
end
|
||||
|
||||
# Sugar for bytecode description
|
||||
def visit(ir_op, cpp = nil)
|
||||
@table ||= []
|
||||
@table << Visitor.new(ir_op, cpp, yield)
|
||||
end
|
||||
|
||||
def visitors
|
||||
@table
|
||||
end
|
||||
|
||||
def switch(expr, cases)
|
||||
Switch.new(expr, cases)
|
||||
end
|
||||
|
||||
def plain(opcode, *args)
|
||||
Leaf.new(instruction_hash[opcode], args.to_a)
|
||||
end
|
||||
|
||||
def empty
|
||||
Empty.new
|
||||
end
|
||||
|
||||
def if_(condition, true_expr, false_expr)
|
||||
If.new(condition, true_expr, false_expr)
|
||||
end
|
||||
|
||||
def prefixed_case(prefix, types, node)
|
||||
types = types.map { |t| "#{prefix}#{t}" }
|
||||
Case.new(types, node)
|
||||
end
|
||||
|
||||
def case_(types, opcode, *args)
|
||||
prefixed_case("compiler::DataType::", types, plain(opcode, *args))
|
||||
end
|
||||
|
||||
def cc_case(types, opcode, *args)
|
||||
prefixed_case("compiler::CC_", types, plain(opcode, *args))
|
||||
end
|
||||
|
||||
def case_switch(types, condition, inner_cases)
|
||||
prefixed_case("compiler::DataType::", types, switch(condition, inner_cases))
|
||||
end
|
||||
|
||||
def case_value(value, node)
|
||||
Case.new([value], node)
|
||||
end
|
||||
|
||||
def case_true(opcode, *args)
|
||||
case_value('1', plain(opcode, *args))
|
||||
end
|
||||
|
||||
def case_true_node(node)
|
||||
case_value('1', node)
|
||||
end
|
||||
|
||||
def case_false(opcode, *args)
|
||||
case_value('0', plain(opcode, *args))
|
||||
end
|
||||
|
||||
def case_false_node(node)
|
||||
case_value('0', node)
|
||||
end
|
||||
|
||||
def generate_arith_op(op)
|
||||
switch("static_cast<int>(#{dst_r} != #{r(0)} && #{dst_r} != #{r(1)})",
|
||||
[case_true(op, r(0), r(1)),
|
||||
case_false_node(is_commutative?(op) ?
|
||||
if_("#{dst_r} == #{r(0)}",
|
||||
plain("#{op}v", r(0), r(1)),
|
||||
plain("#{op}v", r(1), r(0))) :
|
||||
plain(op, r(0), r(1))
|
||||
)
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
# Type/cc cases for instruction selection
|
||||
def i32_types
|
||||
@i32_types ||= %w[BOOL UINT8 INT8 UINT16 INT16 UINT32 INT32]
|
||||
end
|
||||
|
||||
def i64_types
|
||||
@i64_types ||= %w[INT64 UINT64]
|
||||
end
|
||||
|
||||
def f32_types
|
||||
@f32_types ||= %w[FLOAT32]
|
||||
end
|
||||
|
||||
def f64_types
|
||||
@f64_types ||= %w[FLOAT64]
|
||||
end
|
||||
|
||||
def b64_types
|
||||
@b64_types ||= i64_types + f64_types
|
||||
end
|
||||
|
||||
def b32_types
|
||||
@b32_types ||= i32_types + f32_types
|
||||
end
|
||||
|
||||
def void_types
|
||||
@void_types ||= %w[VOID]
|
||||
end
|
||||
|
||||
def cc_cases
|
||||
@cc_cases ||= %w[EQ NE LT LE GT GE]
|
||||
end
|
||||
|
||||
# Switch condition printers
|
||||
def type
|
||||
'inst->GetType()'
|
||||
end
|
||||
|
||||
def src_type
|
||||
'inst->GetInputType(0)'
|
||||
end
|
||||
|
||||
# we could use switch on 'bool' type for if-else purposes, but that hurts clang_tidy
|
||||
def is_acc?(reg)
|
||||
"#{reg} == compiler::ACC_REG_ID"
|
||||
end
|
||||
|
||||
def is_not_acc?(reg)
|
||||
"#{reg} != compiler::ACC_REG_ID"
|
||||
end
|
||||
|
||||
def is_compact?(reg)
|
||||
"#{reg} < NUM_COMPACTLY_ENCODED_REGS"
|
||||
end
|
||||
|
||||
def is_not_compact?(reg)
|
||||
"#{reg} >= NUM_COMPACTLY_ENCODED_REGS"
|
||||
end
|
||||
|
||||
def is_fcmpg?
|
||||
'static_cast<int>(inst->IsFcmpg())'
|
||||
end
|
||||
|
||||
def is_inci?
|
||||
"static_cast<int>(CanConvertToIncI(inst))"
|
||||
end
|
||||
|
||||
def is_commutative?(op)
|
||||
["add", "mul", "and", "or", "xor"].include?(op)
|
||||
end
|
||||
|
||||
def is_arith_iv?
|
||||
"#{is_not_acc?(r(0))} && #{is_not_acc?(dst_r)} && (#{is_compact?(r(0))} || #{is_compact?(dst_r)})"
|
||||
end
|
||||
|
||||
def cast_to_int(val)
|
||||
"static_cast<int>(#{val})"
|
||||
end
|
||||
|
||||
# Operand printers
|
||||
def dst_r
|
||||
'inst->GetDstReg()'
|
||||
end
|
||||
|
||||
def r(num)
|
||||
"inst->GetSrcReg(#{num})"
|
||||
end
|
||||
|
||||
def imm
|
||||
'static_cast<int32_t>(inst->GetImm() & 0xffffffff)'
|
||||
end
|
||||
|
||||
def label
|
||||
'LabelName(inst->GetBasicBlock()->GetTrueSuccessor()->GetId())'
|
||||
end
|
||||
|
||||
def string_id
|
||||
'enc->ir_interface_->GetStringIdByOffset(inst->GetTypeId())'
|
||||
end
|
||||
|
||||
def literalarray_id
|
||||
'enc->ir_interface_->GetLiteralArrayIdByOffset(inst->GetTypeId()).value()'
|
||||
end
|
||||
|
||||
def type_id
|
||||
'enc->ir_interface_->GetTypeIdByOffset(inst->GetTypeId())'
|
||||
end
|
||||
|
||||
def field_id
|
||||
'enc->ir_interface_->GetFieldIdByOffset(inst->GetTypeId())'
|
||||
end
|
||||
|
||||
# Lda/Sta printers
|
||||
def do_lda(instruction)
|
||||
lda = case instruction.src_acc_kind
|
||||
when 32
|
||||
instruction_hash['lda']
|
||||
when 64
|
||||
instruction_hash['lda.64']
|
||||
when 'ref'
|
||||
instruction_hash['lda.obj']
|
||||
end
|
||||
reg_num = if instruction.mnemonic.include?('ldarr') || instruction.mnemonic.include?('stobj') || instruction.mnemonic.include?('ststatic')
|
||||
1
|
||||
elsif instruction.mnemonic.include?('starr')
|
||||
2
|
||||
else
|
||||
0
|
||||
end
|
||||
"if (inst->GetSrcReg(#{reg_num}) != compiler::ACC_REG_ID) {
|
||||
enc->result_.emplace_back(pandasm::Create_#{lda.asm_token}(inst->GetSrcReg(#{reg_num})));
|
||||
}"
|
||||
end
|
||||
|
||||
def do_sta(instruction)
|
||||
sta = case instruction.dst_acc_kind
|
||||
when 32
|
||||
instruction_hash['sta']
|
||||
when 64
|
||||
instruction_hash['sta.64']
|
||||
when 'ref'
|
||||
instruction_hash['sta.obj']
|
||||
end
|
||||
"if (inst->GetDstReg() != compiler::ACC_REG_ID) {
|
||||
enc->result_.emplace_back(pandasm::Create_#{sta.asm_token}(inst->GetDstReg()));
|
||||
}"
|
||||
end
|
||||
|
||||
# Misc printers
|
||||
def visitor_sig(op_name, with_class = true)
|
||||
"void #{'BytecodeGen::' if with_class}Visit#{op_name}(GraphVisitor* v, Inst* inst_base)"
|
||||
end
|
||||
|
||||
# Bytecode description itself
|
||||
|
||||
# Wrap all `insn` declaration in a function to call from template
|
||||
# (because Panda::instructions is initialized only in templates)
|
||||
def call_me_from_template
|
||||
%w[And Xor Or Shl Shr AShr].each do |op|
|
||||
visit(op) do
|
||||
op = op.downcase
|
||||
switch(type,
|
||||
[case_switch(i32_types, cast_to_int(is_not_compact?(r(0))),
|
||||
[case_true_node(if_(is_acc?(dst_r),
|
||||
plain("#{op}2", r(1)),
|
||||
plain("#{op}2v", dst_r, r(1)))),
|
||||
case_false_node(if_("#{is_compact?(dst_r)}",
|
||||
generate_arith_op(op),
|
||||
plain(op, r(0), r(1))))]),
|
||||
case_switch(i64_types, cast_to_int(is_acc?(dst_r)),
|
||||
[case_true("#{op}2.64", r(1)),
|
||||
case_false("#{op}2v.64", dst_r, r(1))])]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
%w[add sub mul div mod].each do |op|
|
||||
visit(op.capitalize) do
|
||||
switch(type,
|
||||
[case_switch(i32_types, cast_to_int(is_not_compact?(r(0))),
|
||||
[case_true_node(if_(is_acc?(dst_r),
|
||||
plain("#{op}2", r(1)),
|
||||
plain("#{op}2v", dst_r, r(1)))),
|
||||
case_false_node(if_("#{is_compact?(dst_r)}",
|
||||
generate_arith_op(op),
|
||||
plain(op, r(0), r(1))))]),
|
||||
case_switch(i64_types, cast_to_int(is_acc?(dst_r)),
|
||||
[case_true("#{op}2.64", r(1)),
|
||||
case_false("#{op}2v.64", dst_r, r(1))]),
|
||||
case_switch(f32_types, cast_to_int(is_acc?(dst_r)),
|
||||
[case_true("f#{op}2", r(1)),
|
||||
case_false("f#{op}2v", dst_r, r(1))]),
|
||||
case_switch(f64_types, cast_to_int(is_acc?(dst_r)),
|
||||
[case_true("f#{op}2.64", r(1)),
|
||||
case_false("f#{op}2v.64", dst_r, r(1))])]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
visit('AddI') do
|
||||
switch(type,
|
||||
[case_switch(i32_types, is_inci?,
|
||||
[case_true('inci', r(0), imm),
|
||||
case_false_node(if_(is_arith_iv?,
|
||||
plain("addiv", dst_r, r(0), imm),
|
||||
plain("addi", imm)))])]
|
||||
)
|
||||
end
|
||||
|
||||
visit('SubI') do
|
||||
switch(type,
|
||||
[case_switch(i32_types, is_inci?,
|
||||
[case_true('inci', r(0), "-(#{imm})"),
|
||||
case_false_node(if_(is_arith_iv?,
|
||||
plain("subiv", dst_r, r(0), imm),
|
||||
plain("subi", imm)))])]
|
||||
)
|
||||
end
|
||||
|
||||
visit('Not') do
|
||||
switch(type,
|
||||
[case_(i32_types, 'not'),
|
||||
case_(i64_types, 'not.64')]
|
||||
)
|
||||
end
|
||||
|
||||
visit('Neg') do
|
||||
switch(type,
|
||||
[case_(i32_types, 'neg'),
|
||||
case_(i64_types, 'neg.64'),
|
||||
case_(f32_types, 'fneg'),
|
||||
case_(f64_types, 'fneg.64')]
|
||||
)
|
||||
end
|
||||
|
||||
visit('Cmp') do
|
||||
switch('inst->GetOperandsType()',
|
||||
[case_(%w[UINT8 UINT16 UINT32], 'ucmp', r(1)),
|
||||
case_(%w[INT64], 'cmp.64', r(1)),
|
||||
case_(%w[UINT64], 'ucmp.64', r(1)),
|
||||
case_switch(['FLOAT32'], is_fcmpg?,
|
||||
[case_true('fcmpg', r(1)),
|
||||
case_false('fcmpl', r(1))]),
|
||||
case_switch(['FLOAT64'], is_fcmpg?,
|
||||
[case_true('fcmpg.64', r(1)),
|
||||
case_false('fcmpl.64', r(1))])]
|
||||
)
|
||||
end
|
||||
|
||||
visit('ReturnVoid') do
|
||||
plain('return.void')
|
||||
end
|
||||
|
||||
visit('Throw') do
|
||||
plain('throw', r(0))
|
||||
end
|
||||
|
||||
visit('NullPtr') do
|
||||
switch(cast_to_int(is_acc?(dst_r)),
|
||||
[case_true('lda.null'),
|
||||
case_false('mov.null', dst_r)]
|
||||
)
|
||||
end
|
||||
|
||||
visit('LoadConstArray') do
|
||||
plain('lda.const', dst_r, literalarray_id)
|
||||
end
|
||||
|
||||
visit('NewArray') do
|
||||
plain('newarr', dst_r, r(1), type_id)
|
||||
end
|
||||
|
||||
visit('LenArray') do
|
||||
plain('lenarr', r(0))
|
||||
end
|
||||
|
||||
visit('LoadArray') do
|
||||
switch(type,
|
||||
[case_(['INT8'], 'ldarr.8', r(0)),
|
||||
case_(['UINT8'], 'ldarru.16', r(0)),
|
||||
case_(['INT16'], 'ldarr.16', r(0)),
|
||||
case_(['UINT16'], 'ldarru.16', r(0)),
|
||||
case_(['INT32', 'UINT32'], 'ldarr', r(0)),
|
||||
case_(['INT64', 'UINT64'], 'ldarr.64', r(0)),
|
||||
case_(['REFERENCE'], 'ldarr.obj', r(0)),
|
||||
case_(['FLOAT32'], 'fldarr.32', r(0)),
|
||||
case_(['FLOAT64'], 'fldarr.64', r(0))]
|
||||
)
|
||||
end
|
||||
|
||||
visit('StoreArray') do
|
||||
switch(type,
|
||||
[case_(['INT8', 'UINT8'], 'starr.8', r(0), r(1)),
|
||||
case_(['INT16', 'UINT16'], 'starr.16', r(0), r(1)),
|
||||
case_(['INT32', 'UINT32'], 'starr', r(0), r(1)),
|
||||
case_(['INT64', 'UINT64'], 'starr.64', r(0), r(1)),
|
||||
case_(['REFERENCE'], 'starr.obj', r(0), r(1)),
|
||||
case_(['FLOAT32'], 'fstarr.32', r(0), r(1)),
|
||||
case_(['FLOAT64'], 'fstarr.64', r(0), r(1))]
|
||||
)
|
||||
end
|
||||
|
||||
visit('CheckCast') do
|
||||
plain('checkcast', type_id)
|
||||
end
|
||||
|
||||
visit('IsInstance') do
|
||||
plain('isinstance', type_id)
|
||||
end
|
||||
|
||||
visit('LoadType') do
|
||||
plain('lda.type', type_id)
|
||||
end
|
||||
|
||||
visit('NewObject', 'if (inst->GetTypeId() == compiler::TypeIdMixin::MEM_PROMISE_CLASS_ID) { return; }') do
|
||||
plain('newobj', dst_r, type_id)
|
||||
end
|
||||
|
||||
# Empty visitors for IR instructions we want to ignore
|
||||
# (Add missing IRs on demand)
|
||||
%w[NullCheck BoundsCheck ZeroCheck NegativeCheck SafePoint
|
||||
InitClass SaveStateDeoptimize RefTypeCheck Phi
|
||||
Try SaveState LoadClass LoadAndInitClass Parameter LoadRuntimeClass].each do |op|
|
||||
visit(op) do
|
||||
empty
|
||||
end
|
||||
end
|
||||
|
||||
%w[MulI DivI ModI ShlI ShrI AShrI AndI OrI XorI].each do |op|
|
||||
visit(op) do
|
||||
switch(type,
|
||||
[case_switch(i32_types, cast_to_int(is_arith_iv?),
|
||||
[case_true("#{op.downcase}v", dst_r, r(0), imm),
|
||||
case_false("#{op.downcase}", imm)])]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
24
static_core/bytecode_optimizer/bytecodeopt_options.h
Normal file
24
static_core/bytecode_optimizer/bytecodeopt_options.h
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef BYTECODEOPT_OPTIONS_H
|
||||
#define BYTECODEOPT_OPTIONS_H
|
||||
|
||||
#include "generated/bytecodeopt_options_gen.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
PANDA_PUBLIC_API extern panda::bytecodeopt::Options OPTIONS;
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // BYTECODEOPT_OPTIONS_H
|
159
static_core/bytecode_optimizer/bytecodeopt_peepholes.cpp
Normal file
159
static_core/bytecode_optimizer/bytecodeopt_peepholes.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "bytecodeopt_peepholes.h"
|
||||
|
||||
#include "libpandafile/bytecode_instruction-inl.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
bool BytecodeOptPeepholes::RunImpl()
|
||||
{
|
||||
VisitGraph();
|
||||
return IsApplied();
|
||||
}
|
||||
|
||||
CallInst *FindCtorCall(Inst *new_object)
|
||||
{
|
||||
auto *graph = new_object->GetBasicBlock()->GetGraph();
|
||||
auto *adapter = graph->GetRuntime();
|
||||
for (auto &user : new_object->GetUsers()) {
|
||||
auto *inst = user.GetInst();
|
||||
if (inst->GetOpcode() == Opcode::NullCheck) {
|
||||
return FindCtorCall(inst);
|
||||
}
|
||||
if (inst->GetOpcode() != Opcode::CallStatic) {
|
||||
continue;
|
||||
}
|
||||
auto call = inst->CastToCallStatic();
|
||||
auto call_first_arg = call->GetInput(0).GetInst();
|
||||
if (call_first_arg->GetOpcode() == Opcode::NewObject) {
|
||||
auto new_object_as_arg = call_first_arg->CastToNewObject();
|
||||
if (new_object_as_arg != new_object) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (adapter->IsConstructor(call->GetCallMethod(), graph->GetLanguage())) {
|
||||
return call;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CallInst *CreateInitObject(compiler::GraphVisitor *v, compiler::ClassInst *load, const CallInst *call_init)
|
||||
{
|
||||
auto *graph = static_cast<BytecodeOptPeepholes *>(v)->GetGraph();
|
||||
auto *init_object = static_cast<CallInst *>(graph->CreateInst(compiler::Opcode::InitObject));
|
||||
init_object->SetType(compiler::DataType::REFERENCE);
|
||||
|
||||
auto input_types_count = call_init->GetInputsCount();
|
||||
init_object->AllocateInputTypes(graph->GetAllocator(), input_types_count);
|
||||
init_object->AddInputType(compiler::DataType::REFERENCE);
|
||||
init_object->AppendInput(load);
|
||||
for (size_t i = 1; i < input_types_count; ++i) {
|
||||
auto input_inst = call_init->GetInput(i).GetInst();
|
||||
init_object->AddInputType(input_inst->GetType());
|
||||
init_object->AppendInput(input_inst);
|
||||
}
|
||||
|
||||
init_object->SetCallMethodId(call_init->GetCallMethodId());
|
||||
init_object->SetCallMethod(static_cast<const CallInst *>(call_init)->GetCallMethod());
|
||||
return init_object;
|
||||
}
|
||||
|
||||
void ReplaceNewObjectUsers(Inst *new_object, Inst *null_check, CallInst *init_object)
|
||||
{
|
||||
for (auto it = new_object->GetUsers().begin(); it != new_object->GetUsers().end();
|
||||
it = new_object->GetUsers().begin()) {
|
||||
auto user = it->GetInst();
|
||||
if (user != null_check) {
|
||||
user->SetInput(it->GetIndex(), init_object);
|
||||
} else {
|
||||
new_object->RemoveUser(&(*it));
|
||||
}
|
||||
}
|
||||
|
||||
// Update throwable instructions data
|
||||
auto graph = new_object->GetBasicBlock()->GetGraph();
|
||||
if (graph->IsInstThrowable(new_object)) {
|
||||
graph->ReplaceThrowableInst(new_object, init_object);
|
||||
}
|
||||
}
|
||||
|
||||
void BytecodeOptPeepholes::VisitNewObject(GraphVisitor *v, Inst *inst)
|
||||
{
|
||||
CallInst *call_init = FindCtorCall(inst);
|
||||
if (call_init == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (inst->GetBasicBlock() != call_init->GetBasicBlock()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The optimization is correct only if there are no side-effects between NewObject and constructor call.
|
||||
// For simplicity, we abort it if any instruction except NullCheck and SaveState appears in-between.
|
||||
// Moreover, when we are inside a try block, local register state also matters, because it may be used inside
|
||||
// catch blocks. In such case we also abort if there are any instructions in corresponding bytecode.
|
||||
const auto graph = static_cast<BytecodeOptPeepholes *>(v)->GetGraph();
|
||||
const size_t newobj_size =
|
||||
BytecodeInstruction::Size( // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
BytecodeInstruction(graph->GetRuntime()->GetMethodCode(graph->GetMethod()) + inst->GetPc()).GetFormat());
|
||||
if (inst->GetBasicBlock()->IsTry() && call_init->GetPc() - inst->GetPc() > newobj_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
Inst *null_check = nullptr;
|
||||
for (auto *i = inst->GetNext(); i != call_init; i = i->GetNext()) {
|
||||
if (i->GetOpcode() != Opcode::SaveState && i->GetOpcode() != Opcode::NullCheck) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (i->GetOpcode() == Opcode::SaveState) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (auto null_check_input : i->GetInputs()) {
|
||||
if (null_check_input.GetInst() == inst) {
|
||||
ASSERT(null_check == nullptr);
|
||||
null_check = i;
|
||||
}
|
||||
}
|
||||
if (null_check == nullptr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
auto load = static_cast<compiler::ClassInst *>(inst->GetInput(0).GetInst());
|
||||
auto *init_object = CreateInitObject(v, load, call_init);
|
||||
call_init->InsertBefore(init_object);
|
||||
init_object->SetPc(call_init->GetPc());
|
||||
|
||||
ReplaceNewObjectUsers(inst, null_check, init_object);
|
||||
inst->ClearFlag(compiler::inst_flags::NO_DCE);
|
||||
if (null_check != nullptr) {
|
||||
null_check->ReplaceUsers(init_object);
|
||||
null_check->ClearFlag(compiler::inst_flags::NO_DCE);
|
||||
null_check->RemoveInputs();
|
||||
null_check->GetBasicBlock()->ReplaceInst(null_check,
|
||||
static_cast<BytecodeOptPeepholes *>(v)->GetGraph()->CreateInstNOP());
|
||||
}
|
||||
ASSERT(!call_init->HasUsers());
|
||||
call_init->ClearFlag(compiler::inst_flags::NO_DCE);
|
||||
|
||||
static_cast<BytecodeOptPeepholes *>(v)->SetIsApplied();
|
||||
}
|
||||
|
||||
} // namespace panda::bytecodeopt
|
92
static_core/bytecode_optimizer/bytecodeopt_peepholes.h
Normal file
92
static_core/bytecode_optimizer/bytecodeopt_peepholes.h
Normal file
@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_BYTECODE_OPTIMIZER_BYTECODEOPT_PEEPHOLES_H_
|
||||
#define PANDA_BYTECODE_OPTIMIZER_BYTECODEOPT_PEEPHOLES_H_
|
||||
|
||||
#include "bytecodeopt_options.h"
|
||||
#include "compiler/optimizer/pass.h"
|
||||
#include "compiler/optimizer/ir/basicblock.h"
|
||||
#include "compiler/optimizer/ir/graph.h"
|
||||
#include "compiler/optimizer/ir/graph_visitor.h"
|
||||
#include "compiler/optimizer/ir/inst.h"
|
||||
#include "libpandabase/utils/arena_containers.h"
|
||||
#include "runtime_adapter.h"
|
||||
|
||||
/*
|
||||
* BytecodeOptPeepholes
|
||||
*
|
||||
* BytecodeOptPeepholes includes now only transformation of NewObject and related instructions into
|
||||
* InitObject
|
||||
*/
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
|
||||
using compiler::BasicBlock;
|
||||
using compiler::CallInst;
|
||||
using compiler::Inst;
|
||||
using compiler::Opcode;
|
||||
|
||||
// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
|
||||
class BytecodeOptPeepholes : public compiler::Optimization, public compiler::GraphVisitor {
|
||||
public:
|
||||
explicit BytecodeOptPeepholes(compiler::Graph *graph) : compiler::Optimization(graph) {}
|
||||
~BytecodeOptPeepholes() override = default;
|
||||
NO_COPY_SEMANTIC(BytecodeOptPeepholes);
|
||||
NO_MOVE_SEMANTIC(BytecodeOptPeepholes);
|
||||
|
||||
bool RunImpl() override;
|
||||
|
||||
const char *GetPassName() const override
|
||||
{
|
||||
return "BytecodeOptPeepholes";
|
||||
}
|
||||
|
||||
bool IsEnable() const override
|
||||
{
|
||||
return OPTIONS.IsBytecodeOptPeepholes();
|
||||
}
|
||||
|
||||
/* This visitor replaces combination of NewObject, SaveState,
|
||||
* NullCheck and CallStatic with InitObject. It is used in order to replace newobj, sta and call
|
||||
* in some ark bytecode with one instruction initobj.
|
||||
*/
|
||||
const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override
|
||||
{
|
||||
return GetGraph()->GetBlocksRPO();
|
||||
}
|
||||
|
||||
static void VisitNewObject(GraphVisitor *v, Inst *inst);
|
||||
|
||||
public:
|
||||
bool IsApplied()
|
||||
{
|
||||
return is_applied_;
|
||||
}
|
||||
|
||||
#include "compiler/optimizer/ir/visitor.inc"
|
||||
|
||||
private:
|
||||
void SetIsApplied()
|
||||
{
|
||||
is_applied_ = true;
|
||||
}
|
||||
|
||||
bool is_applied_ {false};
|
||||
};
|
||||
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // PANDA_BYTECODE_OPTIMIZER_BYTECODEOPT_PEEPHOLES_H_
|
130
static_core/bytecode_optimizer/canonicalization.cpp
Normal file
130
static_core/bytecode_optimizer/canonicalization.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "canonicalization.h"
|
||||
|
||||
#include "compiler/optimizer/ir/basicblock.h"
|
||||
#include "compiler/optimizer/ir/inst.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
|
||||
bool Canonicalization::RunImpl()
|
||||
{
|
||||
Canonicalization visitor(GetGraph());
|
||||
for (auto bb : GetGraph()->GetBlocksRPO()) {
|
||||
for (auto inst : bb->AllInsts()) {
|
||||
if (inst->IsCommutative()) {
|
||||
visitor.VisitCommutative(inst);
|
||||
} else {
|
||||
visitor.VisitInstruction(inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
return visitor.GetStatus();
|
||||
}
|
||||
|
||||
static bool IsDominateReverseInputs(const compiler::Inst *inst)
|
||||
{
|
||||
auto input0 = inst->GetInput(0).GetInst();
|
||||
auto input1 = inst->GetInput(1).GetInst();
|
||||
return input0->IsDominate(input1);
|
||||
}
|
||||
|
||||
static bool ConstantFitsCompareImm(const Inst *cst, uint32_t size)
|
||||
{
|
||||
ASSERT(cst->GetOpcode() == Opcode::Constant);
|
||||
if (compiler::DataType::IsFloatType(cst->GetType())) {
|
||||
return false;
|
||||
}
|
||||
auto val = cst->CastToConstant()->GetIntValue();
|
||||
return (size == compiler::HALF_SIZE) && (val == 0);
|
||||
}
|
||||
|
||||
static bool BetterToSwapCompareInputs(const compiler::Inst *inst, const compiler::Inst *input0,
|
||||
const compiler::Inst *input1)
|
||||
{
|
||||
if (!input0->IsConst()) {
|
||||
return false;
|
||||
}
|
||||
if (!input1->IsConst()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
compiler::DataType::Type type = inst->CastToCompare()->GetOperandsType();
|
||||
uint32_t size = (type == compiler::DataType::UINT64 || type == compiler::DataType::INT64) ? compiler::WORD_SIZE
|
||||
: compiler::HALF_SIZE;
|
||||
return ConstantFitsCompareImm(input0, size) && !ConstantFitsCompareImm(input1, size);
|
||||
}
|
||||
|
||||
static bool SwapInputsIfNecessary(compiler::Inst *inst, const bool necessary)
|
||||
{
|
||||
if (!necessary) {
|
||||
return false;
|
||||
}
|
||||
auto input0 = inst->GetInput(0).GetInst();
|
||||
auto input1 = inst->GetInput(1).GetInst();
|
||||
if ((inst->GetOpcode() == compiler::Opcode::Compare) && !BetterToSwapCompareInputs(inst, input0, input1)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
inst->SwapInputs();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Canonicalization::TrySwapConstantInput(Inst *inst)
|
||||
{
|
||||
return SwapInputsIfNecessary(inst, inst->GetInput(0).GetInst()->IsConst());
|
||||
}
|
||||
|
||||
bool Canonicalization::TrySwapReverseInput(Inst *inst)
|
||||
{
|
||||
return SwapInputsIfNecessary(inst, IsDominateReverseInputs(inst));
|
||||
}
|
||||
|
||||
void Canonicalization::VisitCommutative(Inst *inst)
|
||||
{
|
||||
ASSERT(inst->IsCommutative());
|
||||
ASSERT(inst->GetInputsCount() == 2); // 2 is COMMUTATIVE_INPUT_COUNT
|
||||
if (OPTIONS.GetOptLevel() > 1) {
|
||||
result_ = TrySwapReverseInput(inst);
|
||||
}
|
||||
result_ = TrySwapConstantInput(inst) || result_;
|
||||
}
|
||||
|
||||
// It is not allowed to move a constant input1 with a single user (it's processed Compare instruction).
|
||||
// This is necessary for further merging of the constant and the If instrution in the Lowering pass
|
||||
bool AllowSwap(const compiler::Inst *inst)
|
||||
{
|
||||
auto input1 = inst->GetInput(1).GetInst();
|
||||
if (!input1->IsConst()) {
|
||||
return true;
|
||||
}
|
||||
for (const auto &user : input1->GetUsers()) {
|
||||
if (user.GetInst() != inst) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Canonicalization::VisitCompare([[maybe_unused]] GraphVisitor *v, Inst *inst_base)
|
||||
{
|
||||
auto inst = inst_base->CastToCompare();
|
||||
if (AllowSwap(inst) && SwapInputsIfNecessary(inst, IsDominateReverseInputs(inst))) {
|
||||
auto revert_cc = SwapOperandsConditionCode(inst->GetCc());
|
||||
inst->SetCc(revert_cc);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace panda::bytecodeopt
|
69
static_core/bytecode_optimizer/canonicalization.h
Normal file
69
static_core/bytecode_optimizer/canonicalization.h
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_BYTECODE_OPT_CANONICALIZATION_H
|
||||
#define PANDA_BYTECODE_OPT_CANONICALIZATION_H
|
||||
|
||||
#include "bytecodeopt_options.h"
|
||||
#include "compiler/optimizer/ir/graph.h"
|
||||
#include "compiler/optimizer/pass.h"
|
||||
#include "compiler/optimizer/ir/graph_visitor.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
|
||||
using panda::compiler::BasicBlock;
|
||||
using panda::compiler::Inst;
|
||||
using panda::compiler::Opcode;
|
||||
|
||||
// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
|
||||
class Canonicalization : public compiler::Optimization, public compiler::GraphVisitor {
|
||||
public:
|
||||
explicit Canonicalization(compiler::Graph *graph) : compiler::Optimization(graph) {}
|
||||
~Canonicalization() override = default;
|
||||
NO_COPY_SEMANTIC(Canonicalization);
|
||||
NO_MOVE_SEMANTIC(Canonicalization);
|
||||
|
||||
bool RunImpl() override;
|
||||
const char *GetPassName() const override
|
||||
{
|
||||
return "Canonicalization";
|
||||
}
|
||||
bool IsEnable() const override
|
||||
{
|
||||
return OPTIONS.IsCanonicalization();
|
||||
}
|
||||
|
||||
bool GetStatus() const
|
||||
{
|
||||
return result_;
|
||||
}
|
||||
|
||||
const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override
|
||||
{
|
||||
return GetGraph()->GetBlocksRPO();
|
||||
}
|
||||
|
||||
void VisitCommutative(Inst *inst);
|
||||
void static VisitCompare([[maybe_unused]] GraphVisitor *v, Inst *inst);
|
||||
|
||||
static bool TrySwapReverseInput(Inst *inst);
|
||||
static bool TrySwapConstantInput(Inst *inst);
|
||||
#include "optimizer/ir/visitor.inc"
|
||||
private:
|
||||
bool result_ {false};
|
||||
};
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // PANDA_BYTECODE_OPT_CANONICALIZATION_H
|
96
static_core/bytecode_optimizer/check_resolver.cpp
Normal file
96
static_core/bytecode_optimizer/check_resolver.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "check_resolver.h"
|
||||
#include "compiler/optimizer/ir/basicblock.h"
|
||||
#include "compiler/optimizer/ir/inst.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
|
||||
bool CheckResolver::RunImpl()
|
||||
{
|
||||
bool applied = false;
|
||||
for (auto bb : GetGraph()->GetBlocksRPO()) {
|
||||
for (auto inst : bb->Insts()) {
|
||||
auto op = inst->GetOpcode();
|
||||
|
||||
// replace check
|
||||
if (IsCheck(inst)) {
|
||||
size_t i = (op == compiler::Opcode::BoundsCheck || op == compiler::Opcode::RefTypeCheck) ? 1 : 0;
|
||||
auto input = inst->GetInput(i).GetInst();
|
||||
for (auto &user : inst->GetUsers()) {
|
||||
user.GetInst()->SetFlag(compiler::inst_flags::CAN_THROW);
|
||||
}
|
||||
inst->ReplaceUsers(input);
|
||||
inst->ClearFlag(compiler::inst_flags::NO_DCE); // DCE will remove the check inst
|
||||
applied = true;
|
||||
}
|
||||
|
||||
// set NO_DCE for Div, Mod, LoadArray, LoadStatic and LoadObject
|
||||
if (NeedSetNoDCE(inst)) {
|
||||
inst->SetFlag(compiler::inst_flags::NO_DCE);
|
||||
applied = true;
|
||||
}
|
||||
|
||||
// mark LenArray whose users are not all check as no_dce
|
||||
// mark LenArray as no_hoist in all cases
|
||||
if (inst->GetOpcode() == compiler::Opcode::LenArray) {
|
||||
bool no_dce = !inst->HasUsers();
|
||||
for (const auto &usr : inst->GetUsers()) {
|
||||
if (!IsCheck(usr.GetInst())) {
|
||||
no_dce = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (no_dce) {
|
||||
inst->SetFlag(compiler::inst_flags::NO_DCE);
|
||||
}
|
||||
inst->SetFlag(compiler::inst_flags::NO_HOIST);
|
||||
}
|
||||
}
|
||||
}
|
||||
return applied;
|
||||
}
|
||||
|
||||
bool CheckResolver::NeedSetNoDCE(const compiler::Inst *inst)
|
||||
{
|
||||
switch (inst->GetOpcode()) {
|
||||
case compiler::Opcode::Div:
|
||||
case compiler::Opcode::Mod:
|
||||
case compiler::Opcode::LoadArray:
|
||||
case compiler::Opcode::LoadStatic:
|
||||
case compiler::Opcode::LoadObject:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckResolver::IsCheck(const compiler::Inst *inst)
|
||||
{
|
||||
switch (inst->GetOpcode()) {
|
||||
case compiler::Opcode::BoundsCheck:
|
||||
case compiler::Opcode::NullCheck:
|
||||
case compiler::Opcode::NegativeCheck:
|
||||
case compiler::Opcode::ZeroCheck:
|
||||
case compiler::Opcode::RefTypeCheck:
|
||||
case compiler::Opcode::BoundsCheckI:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace panda::bytecodeopt
|
67
static_core/bytecode_optimizer/check_resolver.h
Normal file
67
static_core/bytecode_optimizer/check_resolver.h
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_CHECK_RESOLVER_H
|
||||
#define PANDA_CHECK_RESOLVER_H
|
||||
|
||||
#include "compiler/optimizer/ir/graph.h"
|
||||
#include "compiler/optimizer/ir/inst.h"
|
||||
#include "compiler/optimizer/pass.h"
|
||||
#include "utils/arena_containers.h"
|
||||
|
||||
/*
|
||||
* Check Resolver.
|
||||
*
|
||||
* Check Resolver is a bytecodeopt-specific pass. In bytecode optimizer, we do
|
||||
* not need all check-instructions, such as BoundsCheck, NullCheck, NegativeCheck
|
||||
* and ZeroCheck, because the throws of these checks will be embedded in their
|
||||
* underlying instructions during runtime.
|
||||
* For the sake of saving ROM size, we can delete these check-instructions. Besides,
|
||||
* when bytecode optimizer optimizes the code in which there exist operations on the
|
||||
* element of an array, in the generated code the redundant asm lenarr will be generated
|
||||
* with ldarr and starr. Here lenarr is generated from IR LenArray and LenArray is an
|
||||
* input of BoundsCheck. CodeGen will encode LenArray but ignore BoundsCheck. That is
|
||||
* why dead lenarr remains. So we can also benefit from the size of generated bytecode
|
||||
* by deleting check-instructions.
|
||||
* However, these LenArray that are generated from asm lenarr should be keeped, as they
|
||||
* may throw in the original code logic. For LoadArray, Div, Mod, LoadStatic and LoadObject,
|
||||
* since they can throw but they are not generated as inputs of check-instructions, We
|
||||
* should keep all such insts.
|
||||
*
|
||||
* For every check-instruction, we replace the corresponding input of its users by the data
|
||||
* flow input. Then we clear its NO_DCE flag such that it can be removed by DCE pass. We set
|
||||
* the NO_DCE flag for the insts that should be keeped.
|
||||
*/
|
||||
namespace panda::bytecodeopt {
|
||||
|
||||
class CheckResolver : public compiler::Optimization {
|
||||
public:
|
||||
explicit CheckResolver(compiler::Graph *graph) : compiler::Optimization(graph) {}
|
||||
~CheckResolver() override = default;
|
||||
NO_COPY_SEMANTIC(CheckResolver);
|
||||
NO_MOVE_SEMANTIC(CheckResolver);
|
||||
|
||||
bool RunImpl() override;
|
||||
static bool IsCheck(const compiler::Inst *inst);
|
||||
static bool NeedSetNoDCE(const compiler::Inst *inst);
|
||||
const char *GetPassName() const override
|
||||
{
|
||||
return "CheckResolver";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // PANDA_CHECK_RESOLVER_H
|
32
static_core/bytecode_optimizer/cmake/coverage.cmake
Normal file
32
static_core/bytecode_optimizer/cmake/coverage.cmake
Normal file
@ -0,0 +1,32 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
option(ENABLE_BYTECODE_OPTIMIZER_COVERAGE "Enable coverage calculation for the bytecode optimizer" false)
|
||||
|
||||
include(${PANDA_ROOT}/cmake/toolchain/coverage/unit_tests_lcov.cmake)
|
||||
|
||||
add_custom_target(bytecode_optimizer_coverage DEPENDS bytecodeopt_unit_tests)
|
||||
|
||||
add_custom_command(TARGET bytecode_optimizer_coverage POST_BUILD
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||
COMMAND bash ${PANDA_ROOT}/bytecode_optimizer/tools/optimizer_coverage.sh --binary-dir=${PANDA_BINARY_ROOT} --root-dir=${PANDA_ROOT}
|
||||
)
|
||||
|
||||
if(ENABLE_BYTECODE_OPTIMIZER_COVERAGE)
|
||||
collect_coverage_for_target(
|
||||
TARGET_NAME bytecode_optimizer_coverage
|
||||
INCLUDE_DIR_PATTERN '*/bytecode_optimizer/*'
|
||||
)
|
||||
else()
|
||||
message(STATUS "Coverage will not be calculated (may be enabled by -DENABLE_BYTECODE_OPTIMIZER_COVERAGE=true ).")
|
||||
endif(ENABLE_BYTECODE_OPTIMIZER_COVERAGE)
|
1850
static_core/bytecode_optimizer/codegen.cpp
Normal file
1850
static_core/bytecode_optimizer/codegen.cpp
Normal file
File diff suppressed because it is too large
Load Diff
169
static_core/bytecode_optimizer/codegen.h
Normal file
169
static_core/bytecode_optimizer/codegen.h
Normal file
@ -0,0 +1,169 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_BYTECODE_OPT_CODEGEN_H
|
||||
#define PANDA_BYTECODE_OPT_CODEGEN_H
|
||||
|
||||
#include "assembler/assembly-function.h"
|
||||
#include "assembler/assembly-ins.h"
|
||||
#include "ins_create_api.h"
|
||||
#include "ir_interface.h"
|
||||
#include "compiler/optimizer/pass.h"
|
||||
#include "compiler/optimizer/ir/basicblock.h"
|
||||
#include "compiler/optimizer/ir/graph.h"
|
||||
#include "compiler/optimizer/ir/graph_visitor.h"
|
||||
#include "utils/logger.h"
|
||||
#include "common.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
|
||||
using compiler::BasicBlock;
|
||||
using compiler::Inst;
|
||||
using compiler::Opcode;
|
||||
|
||||
void DoLdaObj(compiler::Register reg, std::vector<pandasm::Ins> &result);
|
||||
void DoLda(compiler::Register reg, std::vector<pandasm::Ins> &result);
|
||||
void DoLda64(compiler::Register reg, std::vector<pandasm::Ins> &result);
|
||||
void DoSta(compiler::Register reg, std::vector<pandasm::Ins> &result);
|
||||
void DoSta64(compiler::Register reg, std::vector<pandasm::Ins> &result);
|
||||
void DoLdaDyn(compiler::Register reg, std::vector<pandasm::Ins> &result);
|
||||
void DoStaDyn(compiler::Register reg, std::vector<pandasm::Ins> &result);
|
||||
|
||||
// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
|
||||
class BytecodeGen : public compiler::Optimization, public compiler::GraphVisitor {
|
||||
public:
|
||||
explicit BytecodeGen(compiler::Graph *graph, pandasm::Function *function, const BytecodeOptIrInterface *iface)
|
||||
: compiler::Optimization(graph), function_(function), ir_interface_(iface)
|
||||
{
|
||||
}
|
||||
~BytecodeGen() override = default;
|
||||
NO_COPY_SEMANTIC(BytecodeGen);
|
||||
NO_MOVE_SEMANTIC(BytecodeGen);
|
||||
|
||||
bool RunImpl() override;
|
||||
const char *GetPassName() const override
|
||||
{
|
||||
return "BytecodeGen";
|
||||
}
|
||||
std::vector<pandasm::Ins> GetEncodedInstructions() const
|
||||
{
|
||||
return res_;
|
||||
}
|
||||
|
||||
void Reserve(size_t res_size = 0)
|
||||
{
|
||||
if (res_size > 0) {
|
||||
result_.reserve(res_size);
|
||||
}
|
||||
}
|
||||
|
||||
bool GetStatus() const
|
||||
{
|
||||
return success_;
|
||||
}
|
||||
|
||||
const std::vector<pandasm::Ins> &GetResult() const
|
||||
{
|
||||
return result_;
|
||||
}
|
||||
|
||||
std::vector<pandasm::Ins> &&GetResult()
|
||||
{
|
||||
return std::move(result_);
|
||||
}
|
||||
|
||||
static std::string LabelName(uint32_t id)
|
||||
{
|
||||
return "label_" + std::to_string(id);
|
||||
}
|
||||
|
||||
void EmitLabel(const std::string &label)
|
||||
{
|
||||
pandasm::Ins l;
|
||||
l.label = label;
|
||||
l.set_label = true;
|
||||
result_.emplace_back(l);
|
||||
}
|
||||
|
||||
void EmitJump(const BasicBlock *bb);
|
||||
|
||||
void EncodeSpillFillData(const compiler::SpillFillData &sf);
|
||||
void EncodeSta(compiler::Register reg, compiler::DataType::Type type);
|
||||
void AddLineNumber(const Inst *inst, size_t idx);
|
||||
void AddColumnNumber(const Inst *inst, uint32_t idx);
|
||||
|
||||
const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override
|
||||
{
|
||||
return GetGraph()->GetBlocksRPO();
|
||||
}
|
||||
static void VisitSpillFill(GraphVisitor *v, Inst *inst);
|
||||
static void VisitConstant(GraphVisitor *v, Inst *inst);
|
||||
static void VisitCallStatic(GraphVisitor *visitor, Inst *inst);
|
||||
static void VisitCallVirtual(GraphVisitor *visitor, Inst *inst);
|
||||
static void VisitInitObject(GraphVisitor *visitor, Inst *inst);
|
||||
static void VisitCatchPhi(GraphVisitor *visitor, Inst *inst);
|
||||
|
||||
static void VisitIf(GraphVisitor *v, Inst *inst_base);
|
||||
static void VisitIfImm(GraphVisitor *v, Inst *inst_base);
|
||||
static void VisitCast(GraphVisitor *v, Inst *inst_base);
|
||||
static void IfImmZero(GraphVisitor *v, Inst *inst_base);
|
||||
static void IfImmNonZero(GraphVisitor *v, Inst *inst_base);
|
||||
static void IfImm64(GraphVisitor *v, Inst *inst_base);
|
||||
static void VisitIntrinsic(GraphVisitor *v, Inst *inst_base);
|
||||
static void CallHandler(GraphVisitor *visitor, Inst *inst);
|
||||
static void VisitStoreObject(GraphVisitor *v, Inst *inst_base);
|
||||
static void VisitStoreStatic(GraphVisitor *v, Inst *inst_base);
|
||||
static void VisitLoadObject(GraphVisitor *v, Inst *inst_base);
|
||||
static void VisitLoadStatic(GraphVisitor *v, Inst *inst_base);
|
||||
static void VisitLoadString(GraphVisitor *v, Inst *inst_base);
|
||||
static void VisitReturn(GraphVisitor *v, Inst *inst_base);
|
||||
|
||||
static void VisitCastValueToAnyType(GraphVisitor *v, Inst *inst_base);
|
||||
|
||||
static void VisitEcma(GraphVisitor *v, Inst *inst_base);
|
||||
static void IfEcma(GraphVisitor *v, compiler::IfInst *inst);
|
||||
|
||||
#include "generated/codegen_visitors.inc"
|
||||
|
||||
#include "generated/insn_selection.h"
|
||||
|
||||
void VisitDefault(Inst *inst) override
|
||||
{
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER) << "Opcode " << compiler::GetOpcodeString(inst->GetOpcode())
|
||||
<< " not yet implemented in codegen";
|
||||
success_ = false;
|
||||
}
|
||||
|
||||
#include "compiler/optimizer/ir/visitor.inc"
|
||||
|
||||
private:
|
||||
void AppendCatchBlock(uint32_t type_id, const compiler::BasicBlock *try_begin, const compiler::BasicBlock *try_end,
|
||||
const compiler::BasicBlock *catch_begin, const compiler::BasicBlock *catch_end = nullptr);
|
||||
void VisitTryBegin(const compiler::BasicBlock *bb);
|
||||
|
||||
private:
|
||||
pandasm::Function *function_;
|
||||
const BytecodeOptIrInterface *ir_interface_;
|
||||
|
||||
std::vector<pandasm::Ins> res_;
|
||||
std::vector<pandasm::Function::CatchBlock> catch_blocks_;
|
||||
|
||||
bool success_ {true};
|
||||
std::vector<pandasm::Ins> result_;
|
||||
};
|
||||
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // PANDA_BYTECODE_OPT_CODEGEN_H
|
95
static_core/bytecode_optimizer/common.cpp
Normal file
95
static_core/bytecode_optimizer/common.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "compiler/optimizer/ir/basicblock.h"
|
||||
#include "compiler/optimizer/ir/graph.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
|
||||
uint8_t AccReadIndex(const compiler::Inst *inst)
|
||||
{
|
||||
// For calls we cannot tell static index for acc position, thus
|
||||
// ensure that we don't invoke this for calls
|
||||
ASSERT(!inst->IsCall());
|
||||
|
||||
switch (inst->GetOpcode()) {
|
||||
case compiler::Opcode::LoadArray:
|
||||
case compiler::Opcode::StoreObject:
|
||||
case compiler::Opcode::StoreStatic:
|
||||
case compiler::Opcode::NewArray:
|
||||
return 1U;
|
||||
case compiler::Opcode::StoreArray:
|
||||
return 2U;
|
||||
default: {
|
||||
if (inst->IsIntrinsic() && inst->IsAccRead()) {
|
||||
ASSERT(inst->GetBasicBlock()->GetGraph()->IsDynamicMethod());
|
||||
ASSERT(inst->GetInputsCount() >= 2U);
|
||||
return inst->GetInputsCount() - 2U;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This method is used by bytecode optimizer's codegen.
|
||||
bool CanConvertToIncI(const compiler::BinaryImmOperation *binop)
|
||||
{
|
||||
ASSERT(binop->GetBasicBlock()->GetGraph()->IsRegAllocApplied());
|
||||
ASSERT(binop->GetOpcode() == compiler::Opcode::AddI || binop->GetOpcode() == compiler::Opcode::SubI);
|
||||
|
||||
// IncI works on the same register.
|
||||
if (binop->GetSrcReg(0) != binop->GetDstReg()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// IncI cannot write accumulator.
|
||||
if (binop->GetSrcReg(0) == compiler::ACC_REG_ID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// IncI users cannot read from accumulator.
|
||||
// While Addi/SubI stores the output in accumulator, IncI works directly on registers.
|
||||
for (const auto &user : binop->GetUsers()) {
|
||||
const auto *uinst = user.GetInst();
|
||||
|
||||
if (uinst->IsCall()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const uint8_t index = AccReadIndex(uinst);
|
||||
if (uinst->GetInput(index).GetInst() == binop && uinst->GetSrcReg(index) == compiler::ACC_REG_ID) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr uint64_t BITMASK = 0xffffffff;
|
||||
// Define min and max values of i4 type.
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
constexpr int32_t min = -8;
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
constexpr int32_t max = 7;
|
||||
|
||||
int32_t imm = binop->GetImm() & BITMASK;
|
||||
// Note: subi 3 is the same as inci v2, -3.
|
||||
if (binop->GetOpcode() == compiler::Opcode::SubI) {
|
||||
imm = -imm;
|
||||
}
|
||||
|
||||
// IncI works only with 4 bits immediates.
|
||||
return imm >= min && imm <= max;
|
||||
}
|
||||
|
||||
} // namespace panda::bytecodeopt
|
40
static_core/bytecode_optimizer/common.h
Normal file
40
static_core/bytecode_optimizer/common.h
Normal file
@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_BYTECODE_OPTIMIZER_COMMON_H
|
||||
#define PANDA_BYTECODE_OPTIMIZER_COMMON_H
|
||||
|
||||
#include "compiler/optimizer/ir/constants.h"
|
||||
#include "compiler/optimizer/ir/inst.h"
|
||||
|
||||
namespace panda::compiler {
|
||||
class BinaryImmOperation;
|
||||
} // namespace panda::compiler
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
static constexpr compiler::Register MIN_REGISTER_NUMBER = 0;
|
||||
static constexpr compiler::Register MAX_NUM_SHORT_CALL_ARGS = 2;
|
||||
static constexpr compiler::Register MAX_NUM_NON_RANGE_ARGS = 4;
|
||||
static constexpr compiler::Register MAX_NUM_INPUTS = MAX_NUM_NON_RANGE_ARGS;
|
||||
static constexpr panda::compiler::Register NUM_COMPACTLY_ENCODED_REGS = 16;
|
||||
[[maybe_unused]] static constexpr compiler::Register MAX_8_BIT_REG = 255 - 1U; // exclude INVALID_REG
|
||||
|
||||
// Get the position where accumulator read happens.
|
||||
uint8_t AccReadIndex(const compiler::Inst *inst);
|
||||
|
||||
bool CanConvertToIncI(const compiler::BinaryImmOperation *binop);
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // PANDA_BYTECODE_OPTIMIZER_COMMON_H
|
354
static_core/bytecode_optimizer/const_array_resolver.cpp
Normal file
354
static_core/bytecode_optimizer/const_array_resolver.cpp
Normal file
@ -0,0 +1,354 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "assembler/assembly-literals.h"
|
||||
#include "const_array_resolver.h"
|
||||
#include "compiler/optimizer/ir/basicblock.h"
|
||||
#include "compiler/optimizer/optimizations/peepholes.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
|
||||
static constexpr size_t STOREARRAY_INPUTS_NUM = 3;
|
||||
static constexpr size_t SINGLE_DIM_ARRAY_RANK = 1;
|
||||
static constexpr size_t MIN_ARRAY_ELEMENTS_AMOUNT = 2;
|
||||
|
||||
bool ConstArrayResolver::RunImpl()
|
||||
{
|
||||
if (ir_interface_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!FindConstantArrays()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// delete instructions for storing array elements
|
||||
RemoveArraysFill();
|
||||
|
||||
// replace old NewArray instructions with new SaveState + LoadConst instructions
|
||||
InsertLoadConstArrayInsts();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsPatchAllowedOpcode(Opcode opcode)
|
||||
{
|
||||
switch (opcode) {
|
||||
case Opcode::StoreArray:
|
||||
case Opcode::LoadString:
|
||||
case Opcode::Constant:
|
||||
case Opcode::Cast:
|
||||
case Opcode::SaveState:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static std::optional<compiler::ConstantInst *> GetConstantIfPossible(Inst *inst)
|
||||
{
|
||||
if (inst->GetOpcode() == Opcode::Cast) {
|
||||
auto input = inst->GetInput(0).GetInst();
|
||||
if ((input->GetOpcode() == Opcode::NullPtr) || !input->IsConst()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto constant_inst = compiler::ConstFoldingCastConst(inst, input, true);
|
||||
if (constant_inst != nullptr) {
|
||||
return constant_inst;
|
||||
}
|
||||
}
|
||||
if (inst->IsConst()) {
|
||||
return inst->CastToConstant();
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<std::vector<pandasm::LiteralArray::Literal>> ConstArrayResolver::FillLiteralArray(Inst *inst, size_t size)
|
||||
{
|
||||
std::vector<pandasm::LiteralArray::Literal> literals {size};
|
||||
std::vector<Inst *> store_insts;
|
||||
|
||||
auto next = inst->GetNext();
|
||||
size_t real_size = 0;
|
||||
|
||||
// are looking for instructions for uninterrupted filling the array
|
||||
while (next != nullptr) {
|
||||
// check whether the instruction is allowed inside the filling patch
|
||||
if (!IsPatchAllowedOpcode(next->GetOpcode())) {
|
||||
break;
|
||||
}
|
||||
|
||||
// find instructions for storing array elements
|
||||
if (next->GetOpcode() != Opcode::StoreArray) {
|
||||
next = next->GetNext();
|
||||
continue;
|
||||
}
|
||||
|
||||
auto store_array_inst = next->CastToStoreArray();
|
||||
if (store_array_inst == nullptr || store_array_inst->GetArray() != inst) {
|
||||
break;
|
||||
}
|
||||
|
||||
// get an index of the inserted element if possible
|
||||
auto index_inst = store_array_inst->GetIndex();
|
||||
auto index_const_inst = GetConstantIfPossible(index_inst);
|
||||
if (!index_const_inst) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto index = static_cast<size_t>((*index_const_inst)->GetIntValue());
|
||||
|
||||
if (index >= size) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
pandasm::LiteralArray::Literal literal {};
|
||||
// create a literal from the array element, if possible
|
||||
if (!FillLiteral(store_array_inst, &literal)) {
|
||||
// if not, then we can't create a constant literal array
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// checks if there is free space on the [index] position in the vector
|
||||
pandasm::LiteralArray::Literal default_literal {};
|
||||
if (literals[index] == default_literal) {
|
||||
real_size++;
|
||||
}
|
||||
|
||||
literals[index] = literal;
|
||||
store_insts.push_back(next);
|
||||
next = next->GetNext();
|
||||
}
|
||||
|
||||
// save the literal array only if it is completely filled
|
||||
// or its size exceeds the minimum number of elements to save
|
||||
if (real_size != size || store_insts.size() < MIN_ARRAY_ELEMENTS_AMOUNT) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// save the store instructions for deleting them later
|
||||
const_arrays_fill_.emplace(inst, std::move(store_insts));
|
||||
return std::optional<std::vector<pandasm::LiteralArray::Literal>> {std::move(literals)};
|
||||
}
|
||||
|
||||
void ConstArrayResolver::AddIntroLiterals(pandasm::LiteralArray *lt_ar)
|
||||
{
|
||||
// add an element that stores the array size (it will be stored in the first element)
|
||||
pandasm::LiteralArray::Literal len_lit;
|
||||
len_lit.tag = panda_file::LiteralTag::INTEGER;
|
||||
len_lit.value = static_cast<uint32_t>(lt_ar->literals.size());
|
||||
lt_ar->literals.insert(lt_ar->literals.begin(), len_lit);
|
||||
|
||||
// add an element that stores the array type (it will be stored in the zero element)
|
||||
pandasm::LiteralArray::Literal tag_lit;
|
||||
tag_lit.tag = panda_file::LiteralTag::TAGVALUE;
|
||||
tag_lit.value = static_cast<uint8_t>(lt_ar->literals.back().tag);
|
||||
lt_ar->literals.insert(lt_ar->literals.begin(), tag_lit);
|
||||
}
|
||||
|
||||
bool ConstArrayResolver::IsMultidimensionalArray(compiler::NewArrayInst *inst)
|
||||
{
|
||||
auto array_type = pandasm::Type::FromName(ir_interface_->GetTypeIdByOffset(inst->GetTypeId()));
|
||||
return array_type.GetRank() > SINGLE_DIM_ARRAY_RANK;
|
||||
}
|
||||
|
||||
static bool IsSameBB(Inst *inst1, Inst *inst2)
|
||||
{
|
||||
return inst1->GetBasicBlock() == inst2->GetBasicBlock();
|
||||
}
|
||||
|
||||
static bool IsSameBB(Inst *inst, compiler::BasicBlock *bb)
|
||||
{
|
||||
return inst->GetBasicBlock() == bb;
|
||||
}
|
||||
|
||||
bool ConstArrayResolver::FindConstantArrays()
|
||||
{
|
||||
size_t init_size = ir_interface_->GetLiteralArrayTableSize();
|
||||
|
||||
for (auto bb : GetGraph()->GetBlocksRPO()) {
|
||||
// go through the instructions of the basic block in reverse order
|
||||
// until we meet the instruction for storing an array element
|
||||
auto inst = bb->GetLastInst();
|
||||
while ((inst != nullptr) && IsSameBB(inst, bb)) {
|
||||
if (inst->GetOpcode() != Opcode::StoreArray) {
|
||||
inst = inst->GetPrev();
|
||||
continue;
|
||||
}
|
||||
|
||||
// the patch for creating and filling an array should start with the NewArray instruction
|
||||
auto array_inst = inst->CastToStoreArray()->GetArray();
|
||||
if (array_inst->GetOpcode() != Opcode::NewArray) {
|
||||
inst = inst->GetPrev();
|
||||
continue;
|
||||
}
|
||||
auto new_array_inst = array_inst->CastToNewArray();
|
||||
|
||||
// the instructions included in the patch must be in one basic block
|
||||
if (!IsSameBB(inst, new_array_inst)) {
|
||||
inst = inst->GetPrev();
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO(aantipina): add the ability to save multidimensional arrays
|
||||
if (IsMultidimensionalArray(new_array_inst)) {
|
||||
if (IsSameBB(inst, new_array_inst)) {
|
||||
inst = new_array_inst->GetPrev();
|
||||
} else {
|
||||
inst = inst->GetPrev();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
auto array_size_inst =
|
||||
GetConstantIfPossible(new_array_inst->GetInput(compiler::NewArrayInst::INDEX_SIZE).GetInst());
|
||||
if (array_size_inst == std::nullopt) {
|
||||
inst = new_array_inst->GetPrev();
|
||||
continue;
|
||||
}
|
||||
auto array_size = (*array_size_inst)->CastToConstant()->GetIntValue();
|
||||
if (array_size < MIN_ARRAY_ELEMENTS_AMOUNT) {
|
||||
inst = new_array_inst->GetPrev();
|
||||
continue;
|
||||
}
|
||||
|
||||
// creating a literal array, if possible
|
||||
auto raw_literal_array = FillLiteralArray(new_array_inst, array_size);
|
||||
if (raw_literal_array == std::nullopt) {
|
||||
inst = new_array_inst->GetPrev();
|
||||
continue;
|
||||
}
|
||||
|
||||
pandasm::LiteralArray literal_array(*raw_literal_array);
|
||||
|
||||
// save the type and length of the array in the first two elements
|
||||
AddIntroLiterals(&literal_array);
|
||||
auto id = ir_interface_->GetLiteralArrayTableSize();
|
||||
ir_interface_->StoreLiteralArray(std::to_string(id), std::move(literal_array));
|
||||
|
||||
// save the NewArray instructions for replacing them with LoadConst instructions later
|
||||
const_arrays_init_.emplace(id, new_array_inst);
|
||||
|
||||
inst = new_array_inst->GetPrev();
|
||||
}
|
||||
}
|
||||
|
||||
// the pass worked if the size of the literal array table increased
|
||||
return init_size < ir_interface_->GetLiteralArrayTableSize();
|
||||
}
|
||||
|
||||
void ConstArrayResolver::RemoveArraysFill()
|
||||
{
|
||||
for (const auto &it : const_arrays_fill_) {
|
||||
for (const auto &store_inst : it.second) {
|
||||
store_inst->GetBasicBlock()->RemoveInst(store_inst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ConstArrayResolver::InsertLoadConstArrayInsts()
|
||||
{
|
||||
for (const auto &[id, start_inst] : const_arrays_init_) {
|
||||
auto method = GetGraph()->GetMethod();
|
||||
compiler::LoadConstArrayInst *new_inst = GetGraph()->CreateInstLoadConstArray(REFERENCE, start_inst->GetPc());
|
||||
new_inst->SetTypeId(id);
|
||||
new_inst->SetMethod(method);
|
||||
|
||||
start_inst->ReplaceUsers(new_inst);
|
||||
start_inst->RemoveInputs();
|
||||
|
||||
compiler::SaveStateInst *save_state = GetGraph()->CreateInstSaveState();
|
||||
save_state->SetPc(start_inst->GetPc());
|
||||
save_state->SetMethod(method);
|
||||
save_state->ReserveInputs(0);
|
||||
|
||||
new_inst->SetInput(0, save_state);
|
||||
start_inst->InsertBefore(save_state);
|
||||
start_inst->GetBasicBlock()->ReplaceInst(start_inst, new_inst);
|
||||
}
|
||||
}
|
||||
|
||||
static bool FillPrimitiveLiteral(pandasm::LiteralArray::Literal *literal, panda_file::Type::TypeId type,
|
||||
compiler::ConstantInst *value_inst)
|
||||
{
|
||||
auto tag = pandasm::LiteralArray::GetArrayTagFromComponentType(type);
|
||||
literal->tag = tag;
|
||||
switch (tag) {
|
||||
case panda_file::LiteralTag::ARRAY_U1:
|
||||
literal->value = static_cast<bool>(value_inst->GetInt32Value());
|
||||
return true;
|
||||
case panda_file::LiteralTag::ARRAY_U8:
|
||||
case panda_file::LiteralTag::ARRAY_I8:
|
||||
literal->value = static_cast<uint8_t>(value_inst->GetInt32Value());
|
||||
return true;
|
||||
case panda_file::LiteralTag::ARRAY_U16:
|
||||
case panda_file::LiteralTag::ARRAY_I16:
|
||||
literal->value = static_cast<uint16_t>(value_inst->GetInt32Value());
|
||||
return true;
|
||||
case panda_file::LiteralTag::ARRAY_U32:
|
||||
case panda_file::LiteralTag::ARRAY_I32:
|
||||
literal->value = value_inst->GetInt32Value();
|
||||
return true;
|
||||
case panda_file::LiteralTag::ARRAY_U64:
|
||||
case panda_file::LiteralTag::ARRAY_I64:
|
||||
literal->value = value_inst->GetInt64Value();
|
||||
return true;
|
||||
case panda_file::LiteralTag::ARRAY_F32:
|
||||
literal->value = value_inst->GetFloatValue();
|
||||
return true;
|
||||
case panda_file::LiteralTag::ARRAY_F64:
|
||||
literal->value = value_inst->GetDoubleValue();
|
||||
return true;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ConstArrayResolver::FillLiteral(compiler::StoreInst *store_array_inst, pandasm::LiteralArray::Literal *literal)
|
||||
{
|
||||
if (store_array_inst->GetInputsCount() > STOREARRAY_INPUTS_NUM) {
|
||||
return false;
|
||||
}
|
||||
auto raw_elem_inst = store_array_inst->GetStoredValue();
|
||||
auto new_array_inst = store_array_inst->GetArray();
|
||||
|
||||
auto array_type =
|
||||
pandasm::Type::FromName(ir_interface_->GetTypeIdByOffset(new_array_inst->CastToNewArray()->GetTypeId()));
|
||||
auto component_type = array_type.GetComponentType();
|
||||
auto component_type_name = array_type.GetComponentName();
|
||||
|
||||
if (pandasm::Type::IsPandaPrimitiveType(component_type_name)) {
|
||||
auto value_inst = GetConstantIfPossible(raw_elem_inst);
|
||||
|
||||
if (value_inst == std::nullopt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return FillPrimitiveLiteral(literal, component_type.GetId(), *value_inst);
|
||||
}
|
||||
|
||||
auto string_type =
|
||||
pandasm::Type::FromDescriptor(panda::panda_file::GetStringClassDescriptor(ir_interface_->GetSourceLang()));
|
||||
if ((raw_elem_inst->GetOpcode() == Opcode::LoadString) && (component_type_name == string_type.GetName())) {
|
||||
literal->tag = panda_file::LiteralTag::ARRAY_STRING;
|
||||
std::string string_value = ir_interface_->GetStringIdByOffset(raw_elem_inst->CastToLoadString()->GetTypeId());
|
||||
literal->value = string_value;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace panda::bytecodeopt
|
75
static_core/bytecode_optimizer/const_array_resolver.h
Normal file
75
static_core/bytecode_optimizer/const_array_resolver.h
Normal file
@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_CONST_ARRAY_RESOLVER_H
|
||||
#define PANDA_CONST_ARRAY_RESOLVER_H
|
||||
|
||||
#include "assembler/assembly-function.h"
|
||||
#include "bytecodeopt_options.h"
|
||||
#include "ir_interface.h"
|
||||
#include "compiler/optimizer/ir/graph.h"
|
||||
#include "compiler/optimizer/pass.h"
|
||||
#include "compiler/optimizer/ir/inst.h"
|
||||
#include "compiler/optimizer/optimizations/const_folding.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
using panda::compiler::Inst;
|
||||
using panda::compiler::Opcode;
|
||||
// NOLINTNEXTLINE(google-build-using-namespace)
|
||||
using namespace panda::compiler::DataType;
|
||||
class ConstArrayResolver : public compiler::Optimization {
|
||||
public:
|
||||
explicit ConstArrayResolver(compiler::Graph *graph, BytecodeOptIrInterface *iface)
|
||||
: compiler::Optimization(graph),
|
||||
ir_interface_(iface),
|
||||
const_arrays_init_(graph->GetLocalAllocator()->Adapter()),
|
||||
const_arrays_fill_(graph->GetLocalAllocator()->Adapter())
|
||||
{
|
||||
}
|
||||
|
||||
~ConstArrayResolver() override = default;
|
||||
NO_COPY_SEMANTIC(ConstArrayResolver);
|
||||
NO_MOVE_SEMANTIC(ConstArrayResolver);
|
||||
|
||||
bool RunImpl() override;
|
||||
|
||||
const char *GetPassName() const override
|
||||
{
|
||||
return "ConstArrayResolver";
|
||||
}
|
||||
|
||||
bool IsEnable() const override
|
||||
{
|
||||
return OPTIONS.IsConstArrayResolver();
|
||||
}
|
||||
|
||||
private:
|
||||
bool FindConstantArrays();
|
||||
void RemoveArraysFill();
|
||||
void InsertLoadConstArrayInsts();
|
||||
std::optional<std::vector<pandasm::LiteralArray::Literal>> FillLiteralArray(Inst *inst, size_t size);
|
||||
bool FillLiteral(compiler::StoreInst *store_array_inst, pandasm::LiteralArray::Literal *literal);
|
||||
void AddIntroLiterals(pandasm::LiteralArray *lt_ar);
|
||||
bool IsMultidimensionalArray(compiler::NewArrayInst *inst);
|
||||
|
||||
private:
|
||||
BytecodeOptIrInterface *ir_interface_ {nullptr};
|
||||
ArenaMap<uint32_t, compiler::NewArrayInst *> const_arrays_init_; // const_arrays_[literalarray_id] = new_array_inst
|
||||
ArenaMap<Inst *, std::vector<Inst *>>
|
||||
const_arrays_fill_; // const_arrays_[new_array_inst] = {store_array_inst_1, ... , store_array_inst_n}
|
||||
};
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // PANDA_CONST_ARRAY_RESOLVER_H
|
152
static_core/bytecode_optimizer/ir_interface.h
Normal file
152
static_core/bytecode_optimizer/ir_interface.h
Normal file
@ -0,0 +1,152 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_IR_INTERFACE_H
|
||||
#define PANDA_IR_INTERFACE_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "assembler/assembly-emitter.h"
|
||||
#include "libpandafile/method_data_accessor-inl.h"
|
||||
#include "compiler/optimizer/ir/constants.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
class BytecodeOptIrInterface {
|
||||
public:
|
||||
explicit BytecodeOptIrInterface(const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps,
|
||||
pandasm::Program *prog = nullptr)
|
||||
: prog_(prog), maps_(maps)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~BytecodeOptIrInterface() = default;
|
||||
NO_COPY_SEMANTIC(BytecodeOptIrInterface);
|
||||
NO_MOVE_SEMANTIC(BytecodeOptIrInterface);
|
||||
|
||||
virtual std::string GetMethodIdByOffset(uint32_t offset) const
|
||||
{
|
||||
auto it = maps_->methods.find(offset);
|
||||
ASSERT(it != maps_->methods.cend());
|
||||
|
||||
return std::string(it->second);
|
||||
}
|
||||
|
||||
virtual std::string GetStringIdByOffset(uint32_t offset) const
|
||||
{
|
||||
auto it = maps_->strings.find(offset);
|
||||
ASSERT(it != maps_->strings.cend());
|
||||
|
||||
return std::string(it->second);
|
||||
}
|
||||
|
||||
std::optional<std::string> GetLiteralArrayIdByOffset(uint32_t offset) const
|
||||
{
|
||||
ASSERT(prog_ != nullptr);
|
||||
if (prog_ == nullptr) {
|
||||
return std::nullopt;
|
||||
}
|
||||
auto id = std::to_string(offset);
|
||||
auto it = prog_->literalarray_table.find(id);
|
||||
ASSERT(it != prog_->literalarray_table.end());
|
||||
return it != prog_->literalarray_table.end() ? std::optional<std::string>(id) : std::nullopt;
|
||||
}
|
||||
|
||||
virtual std::string GetTypeIdByOffset(uint32_t offset) const
|
||||
{
|
||||
auto it = maps_->classes.find(offset);
|
||||
ASSERT(it != maps_->classes.cend());
|
||||
|
||||
return std::string(it->second);
|
||||
}
|
||||
|
||||
virtual std::string GetFieldIdByOffset(uint32_t offset) const
|
||||
{
|
||||
auto it = maps_->fields.find(offset);
|
||||
ASSERT(it != maps_->fields.cend());
|
||||
|
||||
return std::string(it->second);
|
||||
}
|
||||
|
||||
std::unordered_map<size_t, pandasm::Ins *> *GetPcInsMap()
|
||||
{
|
||||
return &pc_ins_map_;
|
||||
}
|
||||
|
||||
size_t GetLineNumberByPc(size_t pc) const
|
||||
{
|
||||
if (pc == compiler::INVALID_PC || pc_ins_map_.empty()) {
|
||||
return 0;
|
||||
}
|
||||
auto iter = pc_ins_map_.find(pc);
|
||||
if (iter == pc_ins_map_.end()) {
|
||||
return 0;
|
||||
}
|
||||
return iter->second->ins_debug.line_number;
|
||||
}
|
||||
|
||||
uint32_t GetColumnNumberByPc(size_t pc) const
|
||||
{
|
||||
if (pc == compiler::INVALID_PC || pc_ins_map_.empty()) {
|
||||
return compiler::INVALID_COLUMN_NUM;
|
||||
}
|
||||
auto iter = pc_ins_map_.find(pc);
|
||||
if (iter == pc_ins_map_.end()) {
|
||||
return compiler::INVALID_COLUMN_NUM;
|
||||
}
|
||||
|
||||
return iter->second->ins_debug.column_number;
|
||||
}
|
||||
|
||||
void ClearPcInsMap()
|
||||
{
|
||||
pc_ins_map_.clear();
|
||||
}
|
||||
|
||||
void StoreLiteralArray(const std::string &id, pandasm::LiteralArray &&literalarray)
|
||||
{
|
||||
ASSERT(prog_ != nullptr);
|
||||
if (prog_ == nullptr) {
|
||||
return;
|
||||
}
|
||||
prog_->literalarray_table.emplace(id, std::move(literalarray));
|
||||
}
|
||||
|
||||
size_t GetLiteralArrayTableSize() const
|
||||
{
|
||||
ASSERT(prog_ != nullptr);
|
||||
if (prog_ == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
return prog_->literalarray_table.size();
|
||||
}
|
||||
|
||||
bool IsMapsSet() const
|
||||
{
|
||||
return maps_ != nullptr;
|
||||
}
|
||||
|
||||
panda_file::SourceLang GetSourceLang()
|
||||
{
|
||||
return prog_ != nullptr ? prog_->lang : panda_file::SourceLang::PANDA_ASSEMBLY;
|
||||
}
|
||||
|
||||
private:
|
||||
pandasm::Program *prog_ {nullptr};
|
||||
const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps_ {nullptr};
|
||||
std::unordered_map<size_t, pandasm::Ins *> pc_ins_map_;
|
||||
};
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // PANDA_IR_INTERFACE_H
|
369
static_core/bytecode_optimizer/optimize_bytecode.cpp
Normal file
369
static_core/bytecode_optimizer/optimize_bytecode.cpp
Normal file
@ -0,0 +1,369 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "optimize_bytecode.h"
|
||||
|
||||
#include "assembler/assembly-emitter.h"
|
||||
#include "assembler/extensions/extensions.h"
|
||||
#include "bytecode_instruction.h"
|
||||
#include "bytecodeopt_options.h"
|
||||
#include "bytecodeopt_peepholes.h"
|
||||
#include "canonicalization.h"
|
||||
#include "check_resolver.h"
|
||||
#include "codegen.h"
|
||||
#include "common.h"
|
||||
#include "const_array_resolver.h"
|
||||
#include "compiler/optimizer/ir/constants.h"
|
||||
#include "compiler/optimizer/ir_builder/ir_builder.h"
|
||||
#include "compiler/optimizer/ir_builder/pbc_iterator.h"
|
||||
#include "compiler/optimizer/optimizations/branch_elimination.h"
|
||||
#include "compiler/optimizer/optimizations/code_sink.h"
|
||||
#include "compiler/optimizer/optimizations/cse.h"
|
||||
#include "compiler/optimizer/optimizations/cleanup.h"
|
||||
#include "compiler/optimizer/optimizations/if_merging.h"
|
||||
#include "compiler/optimizer/optimizations/licm.h"
|
||||
#include "compiler/optimizer/optimizations/lowering.h"
|
||||
#include "compiler/optimizer/optimizations/lse.h"
|
||||
#include "compiler/optimizer/optimizations/move_constants.h"
|
||||
#include "compiler/optimizer/optimizations/peepholes.h"
|
||||
#include "compiler/optimizer/optimizations/regalloc/reg_alloc.h"
|
||||
#include "compiler/optimizer/optimizations/vn.h"
|
||||
#include "libpandabase/mem/arena_allocator.h"
|
||||
#include "libpandabase/mem/pool_manager.h"
|
||||
#include "libpandafile/class_data_accessor.h"
|
||||
#include "libpandafile/class_data_accessor-inl.h"
|
||||
#include "libpandafile/method_data_accessor.h"
|
||||
#include "reg_acc_alloc.h"
|
||||
#include "reg_encoder.h"
|
||||
#include "runtime_adapter.h"
|
||||
|
||||
#include <regex>
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
// NOLINTNEXTLINE(fuchsia-statically-constructed-objects)
|
||||
panda::bytecodeopt::Options OPTIONS("");
|
||||
|
||||
template <typename T>
|
||||
constexpr void RunOpts(compiler::Graph *graph, [[maybe_unused]] BytecodeOptIrInterface *iface)
|
||||
{
|
||||
graph->RunPass<compiler::Cleanup>(false);
|
||||
#ifndef NDEBUG
|
||||
// NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
|
||||
if constexpr (std::is_same_v<T, compiler::Lowering>) {
|
||||
graph->SetLowLevelInstructionsEnabled();
|
||||
}
|
||||
#endif // NDEBUG
|
||||
// NOLINTNEXTLINE(readability-braces-around-statements, readability-misleading-indentation)
|
||||
if constexpr (std::is_same_v<T, ConstArrayResolver>) {
|
||||
graph->RunPass<ConstArrayResolver>(iface);
|
||||
// NOLINTNEXTLINE(readability-misleading-indentation)
|
||||
} else {
|
||||
graph->RunPass<T>();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename First, typename Second, typename... Rest>
|
||||
constexpr void RunOpts(compiler::Graph *graph, BytecodeOptIrInterface *iface = nullptr)
|
||||
{
|
||||
RunOpts<First>(graph, iface);
|
||||
RunOpts<Second, Rest...>(graph, iface);
|
||||
}
|
||||
|
||||
bool RunOptimizations(compiler::Graph *graph, BytecodeOptIrInterface *iface)
|
||||
{
|
||||
constexpr int OPT_LEVEL_0 = 0;
|
||||
constexpr int OPT_LEVEL_1 = 1;
|
||||
constexpr int OPT_LEVEL_2 = 2;
|
||||
|
||||
if (panda::bytecodeopt::OPTIONS.GetOptLevel() == OPT_LEVEL_0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
graph->RunPass<CheckResolver>();
|
||||
graph->RunPass<compiler::Cleanup>(false);
|
||||
// NB! Canonicalization and compiler::Lowering should be present in all levels
|
||||
// since without Lowering pass, RegEncoder will not work for Compare instructions,
|
||||
// and we will not be able to optimize functions where there is branching.
|
||||
// Lowering can't work without Canonicalization pass.
|
||||
if (graph->IsDynamicMethod()) {
|
||||
RunOpts<compiler::ValNum, compiler::Lowering, compiler::MoveConstants>(graph);
|
||||
} else if (panda::bytecodeopt::OPTIONS.GetOptLevel() == OPT_LEVEL_1) {
|
||||
RunOpts<Canonicalization, compiler::Lowering>(graph);
|
||||
} else if (panda::bytecodeopt::OPTIONS.GetOptLevel() == OPT_LEVEL_2) {
|
||||
// ConstArrayResolver Pass is disabled as it requires fixes for stability
|
||||
RunOpts<ConstArrayResolver, compiler::BranchElimination, compiler::ValNum, compiler::IfMerging, compiler::Cse,
|
||||
compiler::Peepholes, compiler::Licm, compiler::Lse, compiler::ValNum, compiler::Cse, Canonicalization,
|
||||
compiler::Lowering, compiler::MoveConstants, BytecodeOptPeepholes>(graph, iface);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
// this pass should run just before register allocator
|
||||
graph->RunPass<compiler::Cleanup>(false);
|
||||
graph->RunPass<RegAccAlloc>();
|
||||
|
||||
graph->RunPass<compiler::Cleanup>(false);
|
||||
if (!RegAlloc(graph)) {
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER) << "Failed compiler::RegAlloc";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!graph->RunPass<RegEncoder>()) {
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER) << "Failed RegEncoder";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BuildMapFromPcToIns(pandasm::Function &function, BytecodeOptIrInterface &ir_interface,
|
||||
const compiler::Graph *graph, compiler::RuntimeInterface::MethodPtr method_ptr)
|
||||
{
|
||||
function.local_variable_debug.clear();
|
||||
auto *pc_ins_map = ir_interface.GetPcInsMap();
|
||||
pc_ins_map->reserve(function.ins.size());
|
||||
auto instructions_buf = graph->GetRuntime()->GetMethodCode(method_ptr);
|
||||
compiler::BytecodeInstructions instructions(instructions_buf, graph->GetRuntime()->GetMethodCodeSize(method_ptr));
|
||||
size_t idx = 0;
|
||||
for (auto insn : instructions) {
|
||||
pandasm::Ins &ins = function.ins[idx++];
|
||||
pc_ins_map->emplace(instructions.GetPc(insn), &ins);
|
||||
if (idx >= function.ins.size()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ColumnNumberPropagate(pandasm::Function *function)
|
||||
{
|
||||
auto &ins_vec = function->ins;
|
||||
uint32_t cn = compiler::INVALID_COLUMN_NUM;
|
||||
// handle the instructions that are at the beginning of code but do not have column number
|
||||
size_t k = 0;
|
||||
while (k < ins_vec.size() && cn == compiler::INVALID_COLUMN_NUM) {
|
||||
cn = ins_vec[k++].ins_debug.column_number;
|
||||
}
|
||||
if (cn == compiler::INVALID_COLUMN_NUM) {
|
||||
LOG(DEBUG, BYTECODE_OPTIMIZER) << "Failed ColumnNumberPropagate: All insts have invalid column number";
|
||||
return;
|
||||
}
|
||||
for (size_t j = 0; j < k - 1; j++) {
|
||||
ins_vec[j].ins_debug.SetColumnNumber(cn);
|
||||
}
|
||||
|
||||
// handle other instructions that do not have column number
|
||||
for (; k < ins_vec.size(); k++) {
|
||||
if (ins_vec[k].ins_debug.column_number != compiler::INVALID_COLUMN_NUM) {
|
||||
cn = ins_vec[k].ins_debug.column_number;
|
||||
} else {
|
||||
ins_vec[k].ins_debug.SetColumnNumber(cn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void LineNumberPropagate(pandasm::Function *function)
|
||||
{
|
||||
if (function == nullptr || function->ins.empty()) {
|
||||
return;
|
||||
}
|
||||
size_t ln = 0;
|
||||
auto &ins_vec = function->ins;
|
||||
|
||||
// handle the instructions that are at the beginning of code but do not have line number
|
||||
size_t i = 0;
|
||||
while (i < ins_vec.size() && ln == 0) {
|
||||
ln = ins_vec[i++].ins_debug.line_number;
|
||||
}
|
||||
if (ln == 0) {
|
||||
LOG(DEBUG, BYTECODE_OPTIMIZER) << "Failed LineNumberPropagate: All insts have invalid line number";
|
||||
return;
|
||||
}
|
||||
for (size_t j = 0; j < i - 1; j++) {
|
||||
ins_vec[j].ins_debug.SetLineNumber(ln);
|
||||
}
|
||||
|
||||
// handle other instructions that do not have line number
|
||||
for (; i < ins_vec.size(); i++) {
|
||||
if (ins_vec[i].ins_debug.line_number != 0) {
|
||||
ln = ins_vec[i].ins_debug.line_number;
|
||||
} else {
|
||||
ins_vec[i].ins_debug.SetLineNumber(ln);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void DebugInfoPropagate(pandasm::Function &function, const compiler::Graph *graph,
|
||||
BytecodeOptIrInterface &ir_interface)
|
||||
{
|
||||
LineNumberPropagate(&function);
|
||||
if (graph->IsDynamicMethod()) {
|
||||
ColumnNumberPropagate(&function);
|
||||
}
|
||||
ir_interface.ClearPcInsMap();
|
||||
}
|
||||
|
||||
static bool SkipFunction(const pandasm::Function &function, const std::string &func_name)
|
||||
{
|
||||
if (panda::bytecodeopt::OPTIONS.WasSetMethodRegex()) {
|
||||
static std::regex rgx(panda::bytecodeopt::OPTIONS.GetMethodRegex());
|
||||
if (!std::regex_match(func_name, rgx)) {
|
||||
LOG(INFO, BYTECODE_OPTIMIZER) << "Skip Function " << func_name << ": Function's name doesn't match regex";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (panda::bytecodeopt::OPTIONS.IsSkipMethodsWithEh() && !function.catch_blocks.empty()) {
|
||||
LOG(INFO, BYTECODE_OPTIMIZER) << "Was not optimized " << func_name << ": Function has catch blocks";
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((function.regs_num + function.GetParamsNum()) > compiler::VIRTUAL_FRAME_SIZE) {
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER) << "Unable to optimize " << func_name
|
||||
<< ": Function frame size is larger than allowed one";
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void SetCompilerOptions(bool is_dynamic)
|
||||
{
|
||||
compiler::OPTIONS.SetCompilerUseSafepoint(false);
|
||||
compiler::OPTIONS.SetCompilerSupportInitObjectInst(true);
|
||||
if (!compiler::OPTIONS.WasSetCompilerMaxBytecodeSize()) {
|
||||
compiler::OPTIONS.SetCompilerMaxBytecodeSize(~0U);
|
||||
}
|
||||
if (is_dynamic) {
|
||||
panda::bytecodeopt::OPTIONS.SetSkipMethodsWithEh(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool OptimizeFunction(pandasm::Program *prog, const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps,
|
||||
const panda_file::MethodDataAccessor &mda, bool is_dynamic, SourceLanguage lang)
|
||||
{
|
||||
ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER};
|
||||
ArenaAllocator local_allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
|
||||
|
||||
SetCompilerOptions(is_dynamic);
|
||||
|
||||
auto ir_interface = BytecodeOptIrInterface(maps, prog);
|
||||
|
||||
auto func_name = ir_interface.GetMethodIdByOffset(mda.GetMethodId().GetOffset());
|
||||
LOG(INFO, BYTECODE_OPTIMIZER) << "Optimizing function: " << func_name;
|
||||
|
||||
auto it = prog->function_table.find(func_name);
|
||||
if (it == prog->function_table.end()) {
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER) << "Cannot find function: " << func_name;
|
||||
return false;
|
||||
}
|
||||
auto method_ptr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(mda.GetMethodId().GetOffset());
|
||||
|
||||
panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile());
|
||||
auto graph = allocator.New<compiler::Graph>(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter, false,
|
||||
nullptr, is_dynamic, true);
|
||||
graph->SetLanguage(lang);
|
||||
|
||||
panda::pandasm::Function &function = it->second;
|
||||
|
||||
if (SkipFunction(function, func_name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// build map from pc to pandasm::ins (to re-build line-number info in BytecodeGen)
|
||||
BuildMapFromPcToIns(function, ir_interface, graph, method_ptr);
|
||||
|
||||
if ((graph == nullptr) || !graph->RunPass<panda::compiler::IrBuilder>()) {
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": IR builder failed!";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (graph->HasIrreducibleLoop()) {
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": Graph has irreducible loop!";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!RunOptimizations(graph, &ir_interface)) {
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": Running optimizations failed!";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!graph->RunPass<BytecodeGen>(&function, &ir_interface)) {
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER) << "Optimizing " << func_name << ": Code generation failed!";
|
||||
return false;
|
||||
}
|
||||
|
||||
DebugInfoPropagate(function, graph, ir_interface);
|
||||
|
||||
function.value_of_first_param =
|
||||
static_cast<int64_t>(graph->GetStackSlotsCount()) - 1; // Work-around promotion rules
|
||||
function.regs_num = static_cast<size_t>(function.value_of_first_param + 1);
|
||||
|
||||
if (auto frame_size = function.regs_num + function.GetParamsNum(); frame_size >= NUM_COMPACTLY_ENCODED_REGS) {
|
||||
LOG(INFO, BYTECODE_OPTIMIZER) << "Function " << func_name << " has frame size " << frame_size;
|
||||
}
|
||||
|
||||
LOG(DEBUG, BYTECODE_OPTIMIZER) << "Optimized " << func_name;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OptimizePandaFile(pandasm::Program *prog, const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps,
|
||||
const std::string &pfile_name, bool is_dynamic)
|
||||
{
|
||||
auto pfile = panda_file::OpenPandaFile(pfile_name);
|
||||
if (!pfile) {
|
||||
LOG(FATAL, BYTECODE_OPTIMIZER) << "Can not open binary file: " << pfile_name;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
|
||||
for (uint32_t id : pfile->GetClasses()) {
|
||||
panda_file::File::EntityId record_id {id};
|
||||
|
||||
if (pfile->IsExternal(record_id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
panda_file::ClassDataAccessor cda {*pfile, record_id};
|
||||
auto lang = cda.GetSourceLang().value_or(SourceLanguage::PANDA_ASSEMBLY);
|
||||
|
||||
cda.EnumerateMethods([prog, maps, is_dynamic, lang, &result](panda_file::MethodDataAccessor &mda) {
|
||||
if (!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative()) {
|
||||
result = OptimizeFunction(prog, maps, mda, is_dynamic, lang) && result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool OptimizeBytecode(pandasm::Program *prog, const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps,
|
||||
const std::string &pandafile_name, bool is_dynamic, bool has_memory_pool)
|
||||
{
|
||||
ASSERT(prog != nullptr);
|
||||
ASSERT(maps != nullptr);
|
||||
|
||||
if (!has_memory_pool) {
|
||||
PoolManager::Initialize(PoolType::MALLOC);
|
||||
}
|
||||
|
||||
auto res = OptimizePandaFile(prog, maps, pandafile_name, is_dynamic);
|
||||
|
||||
if (!has_memory_pool) {
|
||||
PoolManager::Finalize();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
} // namespace panda::bytecodeopt
|
32
static_core/bytecode_optimizer/optimize_bytecode.h
Normal file
32
static_core/bytecode_optimizer/optimize_bytecode.h
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_BYTECODE_OPTIMIZER_OPTIMIZE_BYTECODE_H_
|
||||
#define PANDA_BYTECODE_OPTIMIZER_OPTIMIZE_BYTECODE_H_
|
||||
|
||||
#include "assembler/assembly-emitter.h"
|
||||
#include "assembler/assembly-program.h"
|
||||
#include "compiler/optimizer/ir/graph.h"
|
||||
#include "ir_interface.h"
|
||||
#include "libpandabase/macros.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
PANDA_PUBLIC_API bool RunOptimizations(compiler::Graph *graph, BytecodeOptIrInterface *iface = nullptr);
|
||||
PANDA_PUBLIC_API bool OptimizeBytecode(pandasm::Program *prog, const pandasm::AsmEmitter::PandaFileToPandaAsmMaps *maps,
|
||||
const std::string &pandafile_name, bool is_dynamic = false,
|
||||
bool has_memory_pool = false);
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // PANDA_BYTECODE_OPTIMIZER_OPTIMIZE_BYTECODE_H_
|
58
static_core/bytecode_optimizer/options.yaml
Normal file
58
static_core/bytecode_optimizer/options.yaml
Normal file
@ -0,0 +1,58 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
module:
|
||||
name: bytecodeopt
|
||||
namespace: panda::bytecodeopt
|
||||
|
||||
options:
|
||||
|
||||
- name: opt-level
|
||||
type: int
|
||||
default: 2
|
||||
possible_values:
|
||||
- 0
|
||||
- 1
|
||||
- 2
|
||||
description: |
|
||||
Optimization level for bytecode optimizer. N=0: No optimizations. N=1: New optimizer is turned on, only DCE is applied. N=2: (default): New optimizer is turned on, all compiler's optimizations are turned on.
|
||||
|
||||
- name: canonicalization
|
||||
type: bool
|
||||
default: true
|
||||
description: Enable Canonicalization Pass
|
||||
|
||||
- name: const-resolver
|
||||
type: bool
|
||||
default: true
|
||||
description: Enable Constant Resolver Pass
|
||||
|
||||
- name: method-regex
|
||||
type: std::string
|
||||
default: ""
|
||||
description: A regular expression that specifies methods to optimize
|
||||
|
||||
- name: skip-methods-with-eh
|
||||
type: bool
|
||||
default: false
|
||||
description: Disable optimizer for methods with exceptions handlers
|
||||
|
||||
- name: bytecode-opt-peepholes
|
||||
type: bool
|
||||
default: true
|
||||
description: Enable BytecodeOptPeepholes Pass
|
||||
|
||||
- name: const-array-resolver
|
||||
type: bool
|
||||
default: true
|
||||
description: Enable ConstArray Resolver Pass
|
355
static_core/bytecode_optimizer/reg_acc_alloc.cpp
Normal file
355
static_core/bytecode_optimizer/reg_acc_alloc.cpp
Normal file
@ -0,0 +1,355 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "reg_acc_alloc.h"
|
||||
#include "common.h"
|
||||
#include "compiler/optimizer/ir/basicblock.h"
|
||||
#include "compiler/optimizer/ir/inst.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
|
||||
/// Decide if accumulator register gets dirty between two instructions.
|
||||
bool IsAccWriteBetween(compiler::Inst *src_inst, compiler::Inst *dst_inst)
|
||||
{
|
||||
ASSERT(src_inst != dst_inst);
|
||||
|
||||
compiler::BasicBlock *block = src_inst->GetBasicBlock();
|
||||
compiler::Inst *inst = src_inst->GetNext();
|
||||
|
||||
while (inst != dst_inst) {
|
||||
if (UNLIKELY(inst == nullptr)) {
|
||||
do {
|
||||
// TODO(rtakacs): visit all the successors to get information about the
|
||||
// accumulator usage. Only linear flow is supported right now.
|
||||
if (block->GetSuccsBlocks().size() > 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ASSERT(block->GetSuccsBlocks().size() == 1);
|
||||
block = block->GetSuccessor(0);
|
||||
|
||||
// TODO(rtakacs): only linear flow is supported right now.
|
||||
if (!dst_inst->IsPhi() && block->GetPredsBlocks().size() > 1) {
|
||||
return true;
|
||||
}
|
||||
} while (block->IsEmpty() && !block->HasPhi());
|
||||
|
||||
// Get first phi instruction if exist.
|
||||
// This is requred if dst_inst is a phi node.
|
||||
inst = *(block->AllInsts());
|
||||
} else {
|
||||
if (inst->IsAccWrite()) {
|
||||
if (!inst->IsConst()) {
|
||||
return true;
|
||||
}
|
||||
if (inst->GetDstReg() == compiler::ACC_REG_ID) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (inst->IsAccRead()) {
|
||||
compiler::Inst *input = inst->GetInput(AccReadIndex(inst)).GetInst();
|
||||
|
||||
if (input != src_inst && input->GetDstReg() != compiler::ACC_REG_ID) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
inst = inst->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/// Return true if Phi instruction is marked as optimizable.
|
||||
inline bool RegAccAlloc::IsPhiOptimizable(compiler::Inst *phi) const
|
||||
{
|
||||
ASSERT(phi->GetOpcode() == compiler::Opcode::Phi);
|
||||
return phi->IsMarked(acc_marker_);
|
||||
}
|
||||
|
||||
/// Return true if instruction can read the accumulator.
|
||||
bool RegAccAlloc::IsAccRead(compiler::Inst *inst) const
|
||||
{
|
||||
return UNLIKELY(inst->IsPhi()) ? IsPhiOptimizable(inst) : inst->IsAccRead();
|
||||
}
|
||||
|
||||
static bool IsCommutative(compiler::Inst *inst)
|
||||
{
|
||||
if (inst->GetOpcode() == compiler::Opcode::If) {
|
||||
auto cc = inst->CastToIf()->GetCc();
|
||||
return cc == compiler::ConditionCode::CC_EQ || cc == compiler::ConditionCode::CC_NE;
|
||||
}
|
||||
return inst->IsCommutative();
|
||||
}
|
||||
|
||||
bool UserNeedSwapInputs(compiler::Inst *inst, compiler::Inst *user)
|
||||
{
|
||||
if (!IsCommutative(user)) {
|
||||
return false;
|
||||
}
|
||||
return user->GetInput(AccReadIndex(user)).GetInst() != inst;
|
||||
}
|
||||
|
||||
/// Return true if instruction can write the accumulator.
|
||||
bool RegAccAlloc::IsAccWrite(compiler::Inst *inst) const
|
||||
{
|
||||
return UNLIKELY(inst->IsPhi()) ? IsPhiOptimizable(inst) : inst->IsAccWrite();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decide if user can use accumulator as source.
|
||||
* Do modifications on the order of inputs if necessary.
|
||||
*
|
||||
* Return true, if user can be optimized.
|
||||
*/
|
||||
bool RegAccAlloc::CanUserReadAcc(compiler::Inst *inst, compiler::Inst *user) const
|
||||
{
|
||||
if (user->IsPhi()) {
|
||||
return IsPhiOptimizable(user);
|
||||
}
|
||||
|
||||
if (!IsAccRead(user) || IsAccWriteBetween(inst, user)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool found = false;
|
||||
// Check if the instrucion occures more times as input.
|
||||
// v2. SUB v0, v1
|
||||
// v3. Add v2, v2
|
||||
for (auto input : user->GetInputs()) {
|
||||
compiler::Inst *uinput = input.GetInst();
|
||||
|
||||
if (uinput != inst) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
found = true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &input : user->GetInputs()) {
|
||||
auto input_inst = input.GetInst();
|
||||
if (input_inst != user && input_inst->GetDstReg() == compiler::ACC_REG_ID) {
|
||||
return false;
|
||||
}
|
||||
if (inst->IsPhi() && input_inst->IsConst() &&
|
||||
(input_inst->GetBasicBlock()->GetId() != user->GetBasicBlock()->GetId())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (user->IsLaunchCall()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (user->IsCall()) {
|
||||
return user->GetInputsCount() <= (MAX_NUM_NON_RANGE_ARGS + 1); // +1 for SaveState
|
||||
}
|
||||
|
||||
return user->GetInput(AccReadIndex(user)).GetInst() == inst || IsCommutative(user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if all the Phi inputs and outputs can use the accumulator register.
|
||||
*
|
||||
* Return true, if Phi can be optimized.
|
||||
*/
|
||||
bool RegAccAlloc::IsPhiAccReady(compiler::Inst *phi) const
|
||||
{
|
||||
ASSERT(phi->GetOpcode() == compiler::Opcode::Phi);
|
||||
|
||||
// TODO(rtakacs): there can be cases when the input/output of a Phi is an other Phi.
|
||||
// These cases are not optimized for accumulator.
|
||||
for (auto input : phi->GetInputs()) {
|
||||
compiler::Inst *phi_input = input.GetInst();
|
||||
|
||||
if (!IsAccWrite(phi_input) || IsAccWriteBetween(phi_input, phi)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_set<compiler::Inst *> users_that_required_swap_inputs;
|
||||
for (auto &user : phi->GetUsers()) {
|
||||
compiler::Inst *uinst = user.GetInst();
|
||||
|
||||
if (!CanUserReadAcc(phi, uinst)) {
|
||||
return false;
|
||||
}
|
||||
if (UserNeedSwapInputs(phi, uinst)) {
|
||||
users_that_required_swap_inputs.insert(uinst);
|
||||
}
|
||||
}
|
||||
for (auto uinst : users_that_required_swap_inputs) {
|
||||
uinst->SwapInputs();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* For most insts we can use their src_reg on the acc-read position
|
||||
* to characterise whether we need lda in the codegen pass.
|
||||
*/
|
||||
void RegAccAlloc::SetNeedLda(compiler::Inst *inst, bool need)
|
||||
{
|
||||
if (inst->IsPhi() || inst->IsCatchPhi()) {
|
||||
return;
|
||||
}
|
||||
if (!IsAccRead(inst)) {
|
||||
return;
|
||||
}
|
||||
if (inst->IsCall()) { // we never need lda for calls
|
||||
return;
|
||||
}
|
||||
compiler::Register reg = need ? compiler::INVALID_REG : compiler::ACC_REG_ID;
|
||||
inst->SetSrcReg(AccReadIndex(inst), reg);
|
||||
}
|
||||
|
||||
static inline bool MaybeRegDst(compiler::Inst *inst)
|
||||
{
|
||||
compiler::Opcode opcode = inst->GetOpcode();
|
||||
return inst->IsConst() || inst->IsBinaryInst() || inst->IsBinaryImmInst() || opcode == compiler::Opcode::LoadObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the accumulator usage between instructions.
|
||||
* Eliminate unnecessary register allocations by applying
|
||||
* a special value (ACC_REG_ID) to the destination and
|
||||
* source registers.
|
||||
* This special value is a marker for the code generator
|
||||
* not to produce lda/sta instructions.
|
||||
*/
|
||||
bool RegAccAlloc::RunImpl()
|
||||
{
|
||||
GetGraph()->InitDefaultLocations();
|
||||
// Initialize all source register of all instructions.
|
||||
for (auto block : GetGraph()->GetBlocksRPO()) {
|
||||
for (auto inst : block->Insts()) {
|
||||
if (inst->IsSaveState() || inst->IsCatchPhi()) {
|
||||
continue;
|
||||
}
|
||||
if (inst->IsConst()) {
|
||||
inst->SetFlag(compiler::inst_flags::ACC_WRITE);
|
||||
}
|
||||
for (size_t i = 0; i < inst->GetInputsCount(); ++i) {
|
||||
inst->SetSrcReg(i, compiler::INVALID_REG);
|
||||
if (MaybeRegDst(inst)) {
|
||||
inst->SetDstReg(compiler::INVALID_REG);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Drop the pass if the function contains unsupported opcodes
|
||||
// TODO(rtakacs): support these opcodes.
|
||||
if (!GetGraph()->IsDynamicMethod()) {
|
||||
for (auto block : GetGraph()->GetBlocksRPO()) {
|
||||
for (auto inst : block->AllInsts()) {
|
||||
if (inst->GetOpcode() == compiler::Opcode::Builtin) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark Phi instructions if they can be optimized for acc.
|
||||
for (auto block : GetGraph()->GetBlocksRPO()) {
|
||||
for (auto phi : block->PhiInsts()) {
|
||||
if (IsPhiAccReady(phi)) {
|
||||
phi->SetMarker(acc_marker_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark instructions if they can be optimized for acc.
|
||||
for (auto block : GetGraph()->GetBlocksRPO()) {
|
||||
for (auto inst : block->AllInsts()) {
|
||||
if (inst->NoDest() || !IsAccWrite(inst)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool use_acc_dst_reg = true;
|
||||
|
||||
std::unordered_set<compiler::Inst *> users_that_required_swap_inputs;
|
||||
for (auto &user : inst->GetUsers()) {
|
||||
compiler::Inst *uinst = user.GetInst();
|
||||
if (uinst->IsSaveState()) {
|
||||
continue;
|
||||
}
|
||||
if (CanUserReadAcc(inst, uinst)) {
|
||||
if (UserNeedSwapInputs(inst, uinst)) {
|
||||
users_that_required_swap_inputs.insert(uinst);
|
||||
}
|
||||
SetNeedLda(uinst, false);
|
||||
} else {
|
||||
use_acc_dst_reg = false;
|
||||
}
|
||||
}
|
||||
for (auto uinst : users_that_required_swap_inputs) {
|
||||
uinst->SwapInputs();
|
||||
}
|
||||
|
||||
if (use_acc_dst_reg) {
|
||||
inst->SetDstReg(compiler::ACC_REG_ID);
|
||||
} else if (MaybeRegDst(inst)) {
|
||||
inst->ClearFlag(compiler::inst_flags::ACC_WRITE);
|
||||
for (auto &user : inst->GetUsers()) {
|
||||
compiler::Inst *uinst = user.GetInst();
|
||||
if (uinst->IsSaveState()) {
|
||||
continue;
|
||||
}
|
||||
SetNeedLda(uinst, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto inst : block->Insts()) {
|
||||
if (inst->GetInputsCount() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (inst->IsCall()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
compiler::Inst *input = inst->GetInput(AccReadIndex(inst)).GetInst();
|
||||
|
||||
if (IsAccWriteBetween(input, inst)) {
|
||||
input->SetDstReg(compiler::INVALID_REG);
|
||||
SetNeedLda(inst, true);
|
||||
|
||||
if (MaybeRegDst(input)) {
|
||||
input->ClearFlag(compiler::inst_flags::ACC_WRITE);
|
||||
for (auto &user : input->GetUsers()) {
|
||||
compiler::Inst *uinst = user.GetInst();
|
||||
SetNeedLda(uinst, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
GetGraph()->SetRegAccAllocApplied();
|
||||
#endif // NDEBUG
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace panda::bytecodeopt
|
61
static_core/bytecode_optimizer/reg_acc_alloc.h
Normal file
61
static_core/bytecode_optimizer/reg_acc_alloc.h
Normal file
@ -0,0 +1,61 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_REG_ACC_ALLOC_H_
|
||||
#define PANDA_REG_ACC_ALLOC_H_
|
||||
|
||||
#include "optimizer/ir/graph.h"
|
||||
#include "optimizer/pass.h"
|
||||
#include "compiler_options.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
|
||||
class RegAccAlloc : public compiler::Optimization {
|
||||
using Optimization::Optimization;
|
||||
|
||||
public:
|
||||
explicit RegAccAlloc(compiler::Graph *graph) : compiler::Optimization(graph), acc_marker_(graph->NewMarker()) {};
|
||||
|
||||
~RegAccAlloc() override = default;
|
||||
NO_COPY_SEMANTIC(RegAccAlloc);
|
||||
NO_MOVE_SEMANTIC(RegAccAlloc);
|
||||
|
||||
bool IsEnable() const override
|
||||
{
|
||||
return compiler::OPTIONS.IsCompilerRegAccAlloc();
|
||||
}
|
||||
|
||||
const char *GetPassName() const override
|
||||
{
|
||||
return "RegAccAlloc";
|
||||
}
|
||||
|
||||
bool RunImpl() override;
|
||||
|
||||
private:
|
||||
bool IsPhiOptimizable(compiler::Inst *phi) const;
|
||||
bool IsAccRead(compiler::Inst *inst) const;
|
||||
bool IsAccWrite(compiler::Inst *inst) const;
|
||||
|
||||
bool CanUserReadAcc(compiler::Inst *inst, compiler::Inst *user) const;
|
||||
bool IsPhiAccReady(compiler::Inst *phi) const;
|
||||
void SetNeedLda(compiler::Inst *inst, bool need);
|
||||
|
||||
compiler::Marker acc_marker_ {0};
|
||||
};
|
||||
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // PANDA_REG_ACC_ALLOC_H_
|
735
static_core/bytecode_optimizer/reg_encoder.cpp
Normal file
735
static_core/bytecode_optimizer/reg_encoder.cpp
Normal file
@ -0,0 +1,735 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "reg_encoder.h"
|
||||
#include "common.h"
|
||||
#include "compiler/optimizer/ir/basicblock.h"
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
|
||||
static bool IsIntrinsicRange(Inst *inst)
|
||||
{
|
||||
if (inst->GetOpcode() != compiler::Opcode::Intrinsic) {
|
||||
return false;
|
||||
}
|
||||
#ifdef ENABLE_BYTECODE_OPT
|
||||
switch (inst->CastToIntrinsic()->GetIntrinsicId()) {
|
||||
#ifdef ARK_INTRINSIC_SET
|
||||
case compiler::RuntimeInterface::IntrinsicId::INTRINSIC_CALLI_RANGE_DYN:
|
||||
case compiler::RuntimeInterface::IntrinsicId::INTRINSIC_CALLI_THIS_RANGE_DYN:
|
||||
case compiler::RuntimeInterface::IntrinsicId::INTRINSIC_NEWOBJ_DYNRANGE:
|
||||
case compiler::RuntimeInterface::IntrinsicId::INTRINSIC_SUPER_CALL:
|
||||
#else
|
||||
case compiler::RuntimeInterface::IntrinsicId::ECMA_CALLIRANGEDYN_PREF_IMM16_V8:
|
||||
case compiler::RuntimeInterface::IntrinsicId::ECMA_CALLITHISRANGEDYN_PREF_IMM16_V8:
|
||||
case compiler::RuntimeInterface::IntrinsicId::ECMA_NEWOBJDYNRANGE_PREF_IMM16_V8:
|
||||
case compiler::RuntimeInterface::IntrinsicId::ECMA_SUPERCALL_PREF_IMM16_V8:
|
||||
case compiler::RuntimeInterface::IntrinsicId::ECMA_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8:
|
||||
#endif
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool CanHoldRange(Inst *inst)
|
||||
{
|
||||
switch (inst->GetOpcode()) {
|
||||
case compiler::Opcode::CallStatic:
|
||||
case compiler::Opcode::CallVirtual:
|
||||
case compiler::Opcode::CallLaunchStatic:
|
||||
case compiler::Opcode::CallLaunchVirtual:
|
||||
case compiler::Opcode::InitObject:
|
||||
return true;
|
||||
case compiler::Opcode::Intrinsic:
|
||||
return IsIntrinsicRange(inst);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static compiler::Register CalculateNumNeededRangeTemps(const compiler::Graph *graph)
|
||||
{
|
||||
compiler::Register ret = 0;
|
||||
|
||||
for (auto bb : graph->GetBlocksRPO()) {
|
||||
for (const auto &inst : bb->AllInsts()) {
|
||||
if (!CanHoldRange(inst)) {
|
||||
continue;
|
||||
}
|
||||
auto nargs = inst->GetInputsCount() - (inst->RequireState() ? 1 : 0);
|
||||
if (inst->GetOpcode() == compiler::Opcode::InitObject) {
|
||||
ASSERT(nargs > 0);
|
||||
nargs -= 1; // exclude LoadAndInitClass
|
||||
}
|
||||
if (inst->GetOpcode() == compiler::Opcode::CallLaunchVirtual ||
|
||||
inst->GetOpcode() == compiler::Opcode::CallLaunchStatic) {
|
||||
ASSERT(nargs > 0);
|
||||
nargs -= 1; // exclude NewObject
|
||||
}
|
||||
if (ret < nargs) {
|
||||
if (nargs > MAX_NUM_NON_RANGE_ARGS || IsIntrinsicRange(inst)) {
|
||||
ret = nargs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool RegEncoder::RunImpl()
|
||||
{
|
||||
ASSERT(state_ == RegEncoderState::IDLE);
|
||||
|
||||
num_max_range_input_ = CalculateNumNeededRangeTemps(GetGraph());
|
||||
|
||||
state_ = RegEncoderState::RENUMBER_ARGS;
|
||||
if (!RenumberArgRegs()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
state_ = RegEncoderState::RESERVE_TEMPS;
|
||||
ASSERT(num_temps_ == 0);
|
||||
|
||||
const auto num_regs = GetNumRegs();
|
||||
|
||||
auto max_num_temps = num_temps_;
|
||||
CalculateNumNeededTemps();
|
||||
|
||||
while (max_num_temps != num_temps_) {
|
||||
ASSERT(num_temps_ > max_num_temps);
|
||||
|
||||
if (num_regs > compiler::VIRTUAL_FRAME_SIZE - num_temps_) { // to avoid overflow
|
||||
return false; // no more free registers left in the frame
|
||||
}
|
||||
|
||||
auto delta = static_cast<compiler::Register>(num_temps_ - max_num_temps);
|
||||
range_temps_start_ += delta;
|
||||
|
||||
RenumberRegs(MIN_REGISTER_NUMBER, delta);
|
||||
|
||||
max_num_temps = num_temps_;
|
||||
CalculateNumNeededTemps();
|
||||
if (num_temps_ == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
num_temps_ = num_temps_ > 0 ? num_temps_ : num_changed_width_;
|
||||
if (num_temps_ > 0 || num_max_range_input_ > 0) {
|
||||
state_ = RegEncoderState::INSERT_SPILLS;
|
||||
InsertSpills();
|
||||
|
||||
auto usage_mask = GetGraph()->GetUsedRegs<compiler::DataType::INT64>();
|
||||
for (compiler::Register r = 0; r < num_regs; r++) {
|
||||
usage_mask->at(num_regs + num_temps_ - r - 1) = usage_mask->at(num_regs - r - 1);
|
||||
}
|
||||
std::fill(usage_mask->begin(), usage_mask->begin() + num_temps_, true);
|
||||
}
|
||||
|
||||
SaveNumLocalsToGraph(GetNumLocalsFromGraph() + num_temps_);
|
||||
state_ = RegEncoderState::IDLE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static panda::compiler::DataType::Type GetRegType(panda::compiler::DataType::Type type)
|
||||
{
|
||||
if (type == panda::compiler::DataType::REFERENCE) {
|
||||
return type;
|
||||
}
|
||||
if (panda::compiler::DataType::Is32Bits(type, Arch::NONE)) {
|
||||
return panda::compiler::DataType::UINT32;
|
||||
}
|
||||
return panda::compiler::DataType::UINT64;
|
||||
}
|
||||
|
||||
static bool RegNeedsRenumbering(panda::compiler::Register r)
|
||||
{
|
||||
return r != panda::compiler::ACC_REG_ID && r != panda::compiler::INVALID_REG;
|
||||
}
|
||||
|
||||
static panda::compiler::Register RenumberReg(const panda::compiler::Register r, const panda::compiler::Register delta)
|
||||
{
|
||||
if (r == panda::compiler::ACC_REG_ID) {
|
||||
return r;
|
||||
}
|
||||
return r + delta;
|
||||
}
|
||||
|
||||
static void RenumberSpillFillRegs(panda::compiler::SpillFillInst *inst, const panda::compiler::Register min_reg,
|
||||
const panda::compiler::Register delta)
|
||||
{
|
||||
for (auto &sf : inst->GetSpillFills()) {
|
||||
if (sf.SrcType() == compiler::LocationType::REGISTER && sf.SrcValue() >= min_reg) {
|
||||
sf.SetSrc(compiler::Location::MakeRegister(RenumberReg(sf.SrcValue(), delta)));
|
||||
}
|
||||
if (sf.DstType() == compiler::LocationType::REGISTER && sf.DstValue() >= min_reg) {
|
||||
sf.SetDst(compiler::Location::MakeRegister(RenumberReg(sf.DstValue(), delta)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RegEncoder::RenumberRegs(const compiler::Register min_reg, const compiler::Register delta)
|
||||
{
|
||||
// Renumbering always advances register number `delta` positions forward,
|
||||
// wrapping around on overflows with well-defined behavour.
|
||||
// Hence the requirement to keep delta unsigned.
|
||||
static_assert(std::is_unsigned<compiler::Register>::value, "compiler::Register must be unsigned");
|
||||
ASSERT(delta > 0);
|
||||
|
||||
for (auto *bb : GetGraph()->GetBlocksRPO()) {
|
||||
for (auto inst : bb->AllInsts()) {
|
||||
// Renumber output of any instruction, if applicable:
|
||||
if (RegNeedsRenumbering(inst->GetDstReg()) && inst->GetDstReg() >= min_reg) {
|
||||
inst->SetDstReg(RenumberReg(inst->GetDstReg(), delta));
|
||||
}
|
||||
|
||||
if (inst->IsPhi() || inst->IsCatchPhi()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Renumber inputs and outputs of SpillFill instructions:
|
||||
if (inst->IsSpillFill()) {
|
||||
RenumberSpillFillRegs(inst->CastToSpillFill(), min_reg, delta);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Fix inputs of common instructions:
|
||||
for (size_t i = 0; i < inst->GetInputsCount(); i++) {
|
||||
if (RegNeedsRenumbering(inst->GetSrcReg(i)) && inst->GetSrcReg(i) >= min_reg) {
|
||||
inst->SetSrcReg(i, RenumberReg(inst->GetSrcReg(i), delta));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RegEncoder::RenumberArgRegs()
|
||||
{
|
||||
const auto usage_mask = GetGraph()->GetUsedRegs<compiler::DataType::INT64>();
|
||||
ASSERT(usage_mask->size() == compiler::VIRTUAL_FRAME_SIZE);
|
||||
|
||||
auto frame_size = static_cast<compiler::Register>(usage_mask->size());
|
||||
const auto num_args = GetNumArgsFromGraph();
|
||||
ASSERT(frame_size >= num_args);
|
||||
|
||||
auto num_non_args = static_cast<compiler::Register>(frame_size - num_args);
|
||||
if (num_max_range_input_ > num_non_args) {
|
||||
LOG(DEBUG, BYTECODE_OPTIMIZER) << "RegEncoder: The free regs for range call are not enough";
|
||||
return false;
|
||||
}
|
||||
|
||||
compiler::Register num_locals = 0;
|
||||
if (num_non_args != 0) {
|
||||
while (num_locals != num_non_args && usage_mask->at(num_locals)) {
|
||||
++num_locals;
|
||||
}
|
||||
}
|
||||
|
||||
compiler::Register num_temps = 0;
|
||||
if (num_locals != num_non_args) {
|
||||
compiler::Register r = num_non_args - 1;
|
||||
while (r < num_non_args && usage_mask->at(r)) {
|
||||
++num_temps;
|
||||
--r;
|
||||
}
|
||||
}
|
||||
|
||||
if (num_locals + num_temps > num_non_args - num_max_range_input_) {
|
||||
LOG(DEBUG, BYTECODE_OPTIMIZER) << "RegEncoder: The free regs for range call are not enough";
|
||||
return false;
|
||||
}
|
||||
|
||||
range_temps_start_ = num_locals;
|
||||
|
||||
bool do_renumber = true;
|
||||
|
||||
if (num_non_args == 0 && num_max_range_input_ == 0) { // all registers are arguments: no need to renumber
|
||||
do_renumber = false;
|
||||
}
|
||||
|
||||
// All free regs will be just enough to encode call.rang: no need to renumber
|
||||
if (num_locals + num_temps + num_max_range_input_ == num_non_args) {
|
||||
do_renumber = false;
|
||||
}
|
||||
|
||||
if (num_temps + num_args == 0) { // no temps and no args: nothing to renumber
|
||||
do_renumber = false;
|
||||
}
|
||||
|
||||
if (do_renumber) {
|
||||
const auto min_reg = static_cast<compiler::Register>(num_non_args - num_temps);
|
||||
ASSERT(min_reg > MIN_REGISTER_NUMBER);
|
||||
|
||||
// Assert that if temps are present, they are marked allocated in the mask:
|
||||
for (compiler::Register r = min_reg; r < min_reg + num_temps; r++) {
|
||||
ASSERT(usage_mask->at(r));
|
||||
}
|
||||
|
||||
// Assert that there are no used regs between locals and temps + arguments:
|
||||
for (compiler::Register r = num_locals; r < min_reg; r++) {
|
||||
ASSERT(!usage_mask->at(r));
|
||||
}
|
||||
|
||||
auto delta = static_cast<compiler::Register>(num_locals + num_temps + num_max_range_input_ - num_non_args);
|
||||
RenumberRegs(min_reg, delta);
|
||||
|
||||
for (compiler::Register r = min_reg; r < frame_size; r++) {
|
||||
usage_mask->at(RenumberReg(r, delta)) = usage_mask->at(r);
|
||||
usage_mask->at(r) = false;
|
||||
}
|
||||
}
|
||||
|
||||
SaveNumLocalsToGraph(num_locals + num_temps + num_max_range_input_);
|
||||
return true;
|
||||
}
|
||||
|
||||
void RegEncoder::InsertSpills()
|
||||
{
|
||||
ASSERT(num_max_range_input_ > 0 || (num_temps_ > 0 && num_temps_ <= MAX_NUM_INPUTS));
|
||||
|
||||
for (auto *bb : GetGraph()->GetBlocksRPO()) {
|
||||
for (auto inst : bb->AllInstsSafe()) {
|
||||
if (inst->GetInputsCount() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
VisitInstruction(inst);
|
||||
// TODO(aantipina): Enable assert here for GetStatus() as soon code generation is fully supported
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RegEncoder::CalculateNumNeededTemps()
|
||||
{
|
||||
num_temps_ = 0;
|
||||
|
||||
for (auto bb : GetGraph()->GetBlocksRPO()) {
|
||||
for (auto inst : bb->AllInstsSafe()) {
|
||||
if (inst->GetInputsCount() == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
VisitInstruction(inst);
|
||||
// TODO(aantipina): Enable here for GetStatus() as soon code generation is fully supported
|
||||
}
|
||||
}
|
||||
|
||||
LOG(DEBUG, BYTECODE_OPTIMIZER) << GetGraph()->GetRuntime()->GetMethodFullName(GetGraph()->GetMethod())
|
||||
<< ": num_temps_ = " << std::to_string(num_temps_);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static void AddMoveBefore(Inst *inst, const T &sp_container)
|
||||
{
|
||||
if (sp_container.empty()) {
|
||||
return;
|
||||
}
|
||||
auto sf_inst = inst->GetBasicBlock()->GetGraph()->CreateInstSpillFill();
|
||||
for (auto const &[src, dst] : sp_container) {
|
||||
ASSERT(src != compiler::ACC_REG_ID);
|
||||
sf_inst->AddMove(src, dst.reg, GetRegType(dst.type));
|
||||
LOG(DEBUG, BYTECODE_OPTIMIZER) << "RegEncoder: Move v" << static_cast<int>(dst.reg) << " <- v"
|
||||
<< static_cast<int>(src) << " was added";
|
||||
}
|
||||
inst->GetBasicBlock()->InsertBefore(sf_inst, inst);
|
||||
}
|
||||
|
||||
static bool IsAccReadPosition(compiler::Inst *inst, size_t pos)
|
||||
{
|
||||
// Calls can have accumulator at any position, return false for them
|
||||
return !inst->IsCall() && inst->IsAccRead() && pos == AccReadIndex(inst);
|
||||
}
|
||||
|
||||
void RegEncoder::InsertSpillsForDynInputsInst(compiler::Inst *inst)
|
||||
{
|
||||
ASSERT(state_ == RegEncoderState::INSERT_SPILLS);
|
||||
ASSERT(inst->IsStaticCall() || inst->IsVirtualCall() || inst->IsInitObject() || inst->IsIntrinsic());
|
||||
|
||||
RegContentMap spill_map(GetGraph()->GetLocalAllocator()->Adapter()); // src -> (dst, src_type), non-callrange
|
||||
RegContentVec spill_vec(GetGraph()->GetLocalAllocator()->Adapter()); // spill_vec is used to handle callrange
|
||||
|
||||
auto nargs = inst->GetInputsCount() - (inst->RequireState() ? 1 : 0);
|
||||
auto start = GetStartInputIndex(inst);
|
||||
bool range = IsIntrinsicRange(inst) || (nargs - start > MAX_NUM_NON_RANGE_ARGS && CanHoldRange(inst));
|
||||
|
||||
compiler::Register temp = range ? range_temps_start_ : 0;
|
||||
|
||||
for (size_t i = start; i < nargs; ++i) {
|
||||
auto src_reg = inst->GetSrcReg(i);
|
||||
auto type = inst->GetInputType(i);
|
||||
|
||||
// do not spillfill for acc-read position. For example, Intrinsic.FSTARR32
|
||||
if (IsAccReadPosition(inst, i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!range) {
|
||||
if (!RegNeedsRenumbering(src_reg) || src_reg < NUM_COMPACTLY_ENCODED_REGS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto res = spill_map.emplace(src_reg, RegContent(temp, type));
|
||||
if (res.second) {
|
||||
inst->SetSrcReg(i, temp++);
|
||||
} else {
|
||||
// Such register is already in map.
|
||||
// It can be ok for cases like: CallStatic v49, v49
|
||||
// Such instructions can be generated by optimizer too.
|
||||
const RegContent ®_cont = res.first->second;
|
||||
inst->SetSrcReg(i, reg_cont.reg);
|
||||
}
|
||||
} else {
|
||||
spill_vec.emplace_back(src_reg, RegContent(temp, type));
|
||||
inst->SetSrcReg(i, temp++);
|
||||
}
|
||||
}
|
||||
|
||||
AddMoveBefore(inst, spill_map);
|
||||
AddMoveBefore(inst, spill_vec);
|
||||
}
|
||||
|
||||
size_t RegEncoder::GetStartInputIndex(compiler::Inst *inst)
|
||||
{
|
||||
return (inst->GetOpcode() == compiler::Opcode::InitObject ||
|
||||
inst->GetOpcode() == compiler::Opcode::CallLaunchStatic ||
|
||||
inst->GetOpcode() == compiler::Opcode::CallLaunchVirtual)
|
||||
? 1
|
||||
: 0; // exclude LoadAndInitClass and NewObject
|
||||
}
|
||||
|
||||
static void AddMoveAfter(Inst *inst, compiler::Register src, RegContent dst)
|
||||
{
|
||||
auto sf_inst = inst->GetBasicBlock()->GetGraph()->CreateInstSpillFill();
|
||||
sf_inst->AddMove(src, dst.reg, dst.type);
|
||||
LOG(DEBUG, BYTECODE_OPTIMIZER) << "RegEncoder: Move v" << static_cast<int>(dst.reg) << " <- v"
|
||||
<< static_cast<int>(src) << " was added";
|
||||
inst->GetBasicBlock()->InsertAfter(sf_inst, inst);
|
||||
}
|
||||
|
||||
static bool IsBoundDstSrc(const compiler::Inst *inst)
|
||||
{
|
||||
if (!inst->IsBinaryInst()) {
|
||||
return false;
|
||||
}
|
||||
auto src0 = inst->GetSrcReg(0);
|
||||
auto src1 = inst->GetSrcReg(1);
|
||||
auto dst = inst->GetDstReg();
|
||||
if (inst->IsCommutative()) {
|
||||
return src0 == dst || src1 == dst;
|
||||
}
|
||||
return src0 == dst;
|
||||
}
|
||||
|
||||
static bool IsMoveAfter(const compiler::Inst *inst)
|
||||
{
|
||||
auto writes_to_dest = inst->GetDstReg() != compiler::ACC_REG_ID;
|
||||
if (inst->IsBinaryImmInst()) {
|
||||
return writes_to_dest;
|
||||
}
|
||||
if (inst->IsBinaryInst()) {
|
||||
return writes_to_dest && IsBoundDstSrc(inst);
|
||||
}
|
||||
switch (inst->GetOpcode()) {
|
||||
case compiler::Opcode::LoadObject:
|
||||
// Special case for LoadObject, because it can be register instruction.
|
||||
return writes_to_dest;
|
||||
case compiler::Opcode::NewArray:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void RegEncoder::InsertSpillsForInst(compiler::Inst *inst)
|
||||
{
|
||||
ASSERT(state_ == RegEncoderState::INSERT_SPILLS);
|
||||
|
||||
RegContentMap spill_map(GetGraph()->GetLocalAllocator()->Adapter()); // src -> (dst, src_type)
|
||||
|
||||
if (inst->IsOperandsDynamic()) {
|
||||
InsertSpillsForDynInputsInst(inst);
|
||||
return;
|
||||
}
|
||||
|
||||
compiler::Register temp = 0;
|
||||
for (size_t i = 0; i < inst->GetInputsCount(); i++) {
|
||||
// TODO(mbolshov): make a better solution to skip instructions, that are not relevant to bytecode_opt
|
||||
if (inst->GetInput(i).GetInst()->GetOpcode() == Opcode::LoadAndInitClass) {
|
||||
continue;
|
||||
}
|
||||
auto reg = inst->GetSrcReg(i);
|
||||
if (RegNeedsRenumbering(reg) && reg >= NUM_COMPACTLY_ENCODED_REGS) {
|
||||
auto res = spill_map.emplace(reg, RegContent(temp, GetRegType(inst->GetInputType(i))));
|
||||
if (res.second) {
|
||||
inst->SetSrcReg(i, temp++);
|
||||
} else {
|
||||
// Such register is already in map.
|
||||
// It can be ok for cases like: and v49, v49
|
||||
// Such instructions can be generated by optimizer too.
|
||||
const RegContent ®_cont = res.first->second;
|
||||
inst->SetSrcReg(i, reg_cont.reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddMoveBefore(inst, spill_map);
|
||||
if (IsMoveAfter(inst)) {
|
||||
auto reg = inst->GetDstReg();
|
||||
if (RegNeedsRenumbering(reg) && reg >= NUM_COMPACTLY_ENCODED_REGS) {
|
||||
inst->SetDstReg(temp);
|
||||
AddMoveAfter(inst, temp, RegContent(reg, GetRegType(inst->GetType())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void IncTempsIfNeeded(compiler::Inst *inst, const compiler::Register reg, compiler::Register &num_temps,
|
||||
compiler::Register &num_changed_width)
|
||||
{
|
||||
if (RegNeedsRenumbering(reg) && reg >= NUM_COMPACTLY_ENCODED_REGS) {
|
||||
num_temps++;
|
||||
if (inst->IsBinaryInst()) {
|
||||
num_changed_width++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RegEncoder::CalculateNumNeededTempsForInst(compiler::Inst *inst)
|
||||
{
|
||||
ASSERT(state_ == RegEncoderState::RESERVE_TEMPS);
|
||||
|
||||
compiler::Register num_temps = 0;
|
||||
compiler::Register num_changed_width = 0;
|
||||
|
||||
if (inst->IsOperandsDynamic()) {
|
||||
if (IsIntrinsicRange(inst)) {
|
||||
return;
|
||||
}
|
||||
ASSERT(inst->IsStaticCall() || inst->IsVirtualCall() || inst->IsInitObject() || inst->IsIntrinsic());
|
||||
|
||||
auto nargs = inst->GetInputsCount() - (inst->RequireState() ? 1 : 0);
|
||||
size_t start = inst->GetOpcode() == compiler::Opcode::InitObject ? 1 : 0;
|
||||
|
||||
if (nargs - start > MAX_NUM_NON_RANGE_ARGS) { // is call.range
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = start; i < nargs; i++) {
|
||||
if (IsAccReadPosition(inst, i)) {
|
||||
continue;
|
||||
}
|
||||
auto reg = inst->GetSrcReg(i);
|
||||
if (RegNeedsRenumbering(reg) && reg >= NUM_COMPACTLY_ENCODED_REGS) {
|
||||
num_temps++;
|
||||
if (inst->IsBinaryInst()) {
|
||||
num_changed_width++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t i = 0; i < inst->GetInputsCount(); i++) {
|
||||
// TODO(mbolshov): make a better solution to skip instructions, that are not relevant to bytecode_opt
|
||||
if (inst->GetInput(i).GetInst()->GetOpcode() == Opcode::LoadAndInitClass) {
|
||||
continue;
|
||||
}
|
||||
IncTempsIfNeeded(inst, inst->GetSrcReg(i), num_temps, num_changed_width);
|
||||
}
|
||||
|
||||
if (IsMoveAfter(inst) && !IsBoundDstSrc(inst)) {
|
||||
IncTempsIfNeeded(inst, inst->GetDstReg(), num_temps, num_changed_width);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(num_temps <= MAX_NUM_INPUTS);
|
||||
|
||||
num_temps_ = std::max(num_temps, num_temps_);
|
||||
num_changed_width_ = std::max(num_changed_width, num_changed_width_);
|
||||
}
|
||||
|
||||
void RegEncoder::Check4Width(compiler::Inst *inst)
|
||||
{
|
||||
switch (state_) {
|
||||
case RegEncoderState::RESERVE_TEMPS: {
|
||||
CalculateNumNeededTempsForInst(inst);
|
||||
break;
|
||||
}
|
||||
case RegEncoderState::INSERT_SPILLS: {
|
||||
InsertSpillsForInst(inst);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void RegEncoder::Check8Width([[maybe_unused]] compiler::Inst *inst)
|
||||
{
|
||||
// TODO(aantipina): implement after it became possible to use register numbers more than 256 (#2697)
|
||||
}
|
||||
|
||||
void RegEncoder::VisitCallStatic(GraphVisitor *visitor, Inst *inst)
|
||||
{
|
||||
CallHelper(visitor, inst);
|
||||
}
|
||||
|
||||
void RegEncoder::VisitCallVirtual(GraphVisitor *visitor, Inst *inst)
|
||||
{
|
||||
CallHelper(visitor, inst);
|
||||
}
|
||||
|
||||
void RegEncoder::VisitInitObject(GraphVisitor *visitor, Inst *inst)
|
||||
{
|
||||
CallHelper(visitor, inst);
|
||||
}
|
||||
|
||||
void RegEncoder::VisitIntrinsic(GraphVisitor *visitor, Inst *inst)
|
||||
{
|
||||
auto re = static_cast<RegEncoder *>(visitor);
|
||||
if (IsIntrinsicRange(inst)) {
|
||||
re->Check4Width(inst->CastToIntrinsic());
|
||||
return;
|
||||
}
|
||||
|
||||
re->Check8Width(inst->CastToIntrinsic());
|
||||
}
|
||||
|
||||
void RegEncoder::VisitLoadObject(GraphVisitor *v, Inst *inst_base)
|
||||
{
|
||||
bool is_acc_type = inst_base->GetDstReg() == compiler::ACC_REG_ID;
|
||||
|
||||
auto re = static_cast<RegEncoder *>(v);
|
||||
auto inst = inst_base->CastToLoadObject();
|
||||
switch (inst->GetType()) {
|
||||
case compiler::DataType::BOOL:
|
||||
case compiler::DataType::UINT8:
|
||||
case compiler::DataType::INT8:
|
||||
case compiler::DataType::UINT16:
|
||||
case compiler::DataType::INT16:
|
||||
case compiler::DataType::UINT32:
|
||||
case compiler::DataType::INT32:
|
||||
case compiler::DataType::INT64:
|
||||
case compiler::DataType::UINT64:
|
||||
case compiler::DataType::FLOAT32:
|
||||
case compiler::DataType::FLOAT64:
|
||||
case compiler::DataType::REFERENCE:
|
||||
if (is_acc_type) {
|
||||
re->Check8Width(inst);
|
||||
} else {
|
||||
re->Check4Width(inst);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER)
|
||||
<< "Wrong DataType for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed";
|
||||
re->success_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RegEncoder::VisitLoadStatic(GraphVisitor *v, Inst *inst_base)
|
||||
{
|
||||
auto re = static_cast<RegEncoder *>(v);
|
||||
auto inst = inst_base->CastToLoadStatic();
|
||||
|
||||
switch (inst->GetType()) {
|
||||
case compiler::DataType::BOOL:
|
||||
case compiler::DataType::UINT8:
|
||||
case compiler::DataType::INT8:
|
||||
case compiler::DataType::UINT16:
|
||||
case compiler::DataType::INT16:
|
||||
case compiler::DataType::UINT32:
|
||||
case compiler::DataType::INT32:
|
||||
case compiler::DataType::INT64:
|
||||
case compiler::DataType::UINT64:
|
||||
case compiler::DataType::FLOAT32:
|
||||
case compiler::DataType::FLOAT64:
|
||||
case compiler::DataType::REFERENCE:
|
||||
return;
|
||||
default:
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER)
|
||||
<< "Wrong DataType for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed";
|
||||
re->success_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RegEncoder::VisitStoreObject(GraphVisitor *v, Inst *inst_base)
|
||||
{
|
||||
bool is_acc_type = inst_base->GetSrcReg(1) == compiler::ACC_REG_ID;
|
||||
|
||||
auto re = static_cast<RegEncoder *>(v);
|
||||
auto inst = inst_base->CastToStoreObject();
|
||||
switch (inst->GetType()) {
|
||||
case compiler::DataType::BOOL:
|
||||
case compiler::DataType::UINT8:
|
||||
case compiler::DataType::INT8:
|
||||
case compiler::DataType::UINT16:
|
||||
case compiler::DataType::INT16:
|
||||
case compiler::DataType::UINT32:
|
||||
case compiler::DataType::INT32:
|
||||
case compiler::DataType::INT64:
|
||||
case compiler::DataType::UINT64:
|
||||
case compiler::DataType::FLOAT32:
|
||||
case compiler::DataType::FLOAT64:
|
||||
case compiler::DataType::REFERENCE:
|
||||
if (is_acc_type) {
|
||||
re->Check8Width(inst);
|
||||
} else {
|
||||
re->Check4Width(inst);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER)
|
||||
<< "Wrong DataType for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed";
|
||||
re->success_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RegEncoder::VisitStoreStatic(GraphVisitor *v, Inst *inst_base)
|
||||
{
|
||||
auto re = static_cast<RegEncoder *>(v);
|
||||
auto inst = inst_base->CastToStoreStatic();
|
||||
|
||||
switch (inst->GetType()) {
|
||||
case compiler::DataType::BOOL:
|
||||
case compiler::DataType::UINT8:
|
||||
case compiler::DataType::INT8:
|
||||
case compiler::DataType::UINT16:
|
||||
case compiler::DataType::INT16:
|
||||
case compiler::DataType::UINT32:
|
||||
case compiler::DataType::INT32:
|
||||
case compiler::DataType::INT64:
|
||||
case compiler::DataType::UINT64:
|
||||
case compiler::DataType::FLOAT32:
|
||||
case compiler::DataType::FLOAT64:
|
||||
case compiler::DataType::REFERENCE:
|
||||
return;
|
||||
default:
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER)
|
||||
<< "Wrong DataType for " << compiler::GetOpcodeString(inst->GetOpcode()) << " failed";
|
||||
re->success_ = false;
|
||||
}
|
||||
}
|
||||
void RegEncoder::VisitSpillFill([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst) {}
|
||||
void RegEncoder::VisitConstant([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst) {}
|
||||
void RegEncoder::VisitLoadString([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst) {}
|
||||
void RegEncoder::VisitReturn([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst) {}
|
||||
void RegEncoder::VisitCatchPhi([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst) {}
|
||||
void RegEncoder::VisitCastValueToAnyType([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst) {}
|
||||
|
||||
#include "generated/check_width.cpp"
|
||||
} // namespace panda::bytecodeopt
|
216
static_core/bytecode_optimizer/reg_encoder.h
Normal file
216
static_core/bytecode_optimizer/reg_encoder.h
Normal file
@ -0,0 +1,216 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef PANDA_REG_ENCODER_H
|
||||
#define PANDA_REG_ENCODER_H
|
||||
|
||||
#include "compiler/optimizer/ir/graph.h"
|
||||
#include "compiler/optimizer/pass.h"
|
||||
#include "compiler/optimizer/ir/inst.h"
|
||||
#include "compiler/optimizer/ir/graph_visitor.h"
|
||||
|
||||
/*
|
||||
* Register Encoder.
|
||||
*
|
||||
* After compiler's register allocation layout of the virtual frame looks like:
|
||||
*
|
||||
* |<-locals->|<-free registers->|<-RegAlloc temps->|<-arguments->|
|
||||
*
|
||||
* where:
|
||||
*
|
||||
* * locals (>= 0) are registers allocated for function's local variables;
|
||||
* * temps (>= 0) are temporary registers that can be allocated by spill-fill
|
||||
* resolver during breaking mov chain cycles;
|
||||
* * arguments (>= 0) are registers allocated for function's arguemnts.
|
||||
*
|
||||
* The size of the frame is fixed (see register allocator for details).
|
||||
*
|
||||
* Locals and temps are allocated densely: if there are more than 0 locals
|
||||
* (or temps) then all registers go strictly in order without "holes".
|
||||
* Space for arguments, however, can contain "holes" (each "hole" corresponds
|
||||
* to an unused argument).
|
||||
*
|
||||
* For locals and temps, it is not guaranteed that their number equals to the
|
||||
* number of registers used in the unoptimized bytecode. Total number of arguments
|
||||
* is of course constant throughout optimization pipeline.
|
||||
*
|
||||
* This pass solves following problems:
|
||||
*
|
||||
* 1. Shift temps and arguments to the left adjacently to locals, and reserve the
|
||||
* range temps from free registers if necessary, consistently changing all register
|
||||
* numbers for affected instructions. After this is done, the virtual frame looks like:
|
||||
*
|
||||
* |<-locals->|<-range temps->|<-RegAlloc temps->|<-arguments->|<-free registers->|
|
||||
*
|
||||
* 2. Check if IR contains any instructions that can encode only [r0, r15] with
|
||||
* actual inputs r16+. If such instructions are found, some lower registers
|
||||
* (starting with r0, but no more than MAX_NUM_INPUTS registers) are reserved as
|
||||
* temps and corresponding spills are emitted where needed. After this is done,
|
||||
* the virtual frame looks like:
|
||||
*
|
||||
* |<-Renumber temps->|<-locals->|<-range temps->|<-RegAlloc temps->|<-arguments->|<-free registers->|
|
||||
*
|
||||
* After the pass:
|
||||
*
|
||||
* * Usage mask is updated accordingly.
|
||||
* * num_locals + num_temps + num_max_range_input is stored to graph with SetStackSlotsCount
|
||||
*/
|
||||
|
||||
namespace panda::bytecodeopt {
|
||||
struct RegContent {
|
||||
// NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
|
||||
compiler::Register reg;
|
||||
// NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
|
||||
compiler::DataType::Type type;
|
||||
|
||||
RegContent() : reg(compiler::INVALID_REG), type(compiler::DataType::NO_TYPE) {}
|
||||
RegContent(compiler::Register r, compiler::DataType::Type t) : reg(r), type(t) {}
|
||||
|
||||
bool operator==(const RegContent &other) const
|
||||
{
|
||||
return reg == other.reg && type == other.type;
|
||||
}
|
||||
|
||||
bool operator!=(const RegContent &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
using RegContentMap = ArenaUnorderedMap<compiler::Register, RegContent>;
|
||||
using RegContentVec = ArenaVector<std::pair<compiler::Register, RegContent>>;
|
||||
|
||||
enum class RegEncoderState { IDLE, RENUMBER_ARGS, RESERVE_TEMPS, INSERT_SPILLS };
|
||||
|
||||
using panda::compiler::BasicBlock;
|
||||
using panda::compiler::Inst;
|
||||
using panda::compiler::Opcode;
|
||||
|
||||
// NOLINTNEXTLINE(fuchsia-multiple-inheritance)
|
||||
class RegEncoder : public compiler::Optimization, public compiler::GraphVisitor {
|
||||
public:
|
||||
explicit RegEncoder(compiler::Graph *graph) : compiler::Optimization(graph) {}
|
||||
|
||||
~RegEncoder() override = default;
|
||||
NO_COPY_SEMANTIC(RegEncoder);
|
||||
NO_MOVE_SEMANTIC(RegEncoder);
|
||||
|
||||
// true: Pass applied successfully
|
||||
// false: Unable to apply pass because of insufficient number of registers
|
||||
bool RunImpl() override;
|
||||
|
||||
const char *GetPassName() const override
|
||||
{
|
||||
return "RegEncoder";
|
||||
}
|
||||
|
||||
void Check4Width(compiler::Inst *inst);
|
||||
void Check8Width(compiler::Inst *inst);
|
||||
|
||||
const ArenaVector<BasicBlock *> &GetBlocksToVisit() const override
|
||||
{
|
||||
return GetGraph()->GetBlocksRPO();
|
||||
}
|
||||
|
||||
static void VisitSpillFill([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
|
||||
static void VisitConstant([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
|
||||
static void VisitCatchPhi([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
|
||||
static void VisitCallStatic(GraphVisitor *v, Inst *inst);
|
||||
static void VisitCallVirtual(GraphVisitor *v, Inst *inst);
|
||||
static void VisitInitObject(GraphVisitor *v, Inst *inst);
|
||||
static void VisitIntrinsic(GraphVisitor *v, Inst *inst);
|
||||
static void VisitLoadObject(GraphVisitor *v, Inst *inst_base);
|
||||
static void VisitLoadStatic(GraphVisitor *v, Inst *inst_base);
|
||||
static void VisitStoreObject(GraphVisitor *v, Inst *inst_base);
|
||||
static void VisitStoreStatic(GraphVisitor *v, Inst *inst_base);
|
||||
static void VisitLoadString([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
|
||||
static void VisitReturn([[maybe_unused]] GraphVisitor *v, [[maybe_unused]] Inst *inst);
|
||||
|
||||
static void VisitCastValueToAnyType(GraphVisitor *v, Inst *inst);
|
||||
|
||||
#include "generated/reg_encoder_visitors.inc"
|
||||
|
||||
#include "generated/check_width.h"
|
||||
|
||||
void VisitDefault(Inst *inst) override
|
||||
{
|
||||
LOG(ERROR, BYTECODE_OPTIMIZER) << "Opcode " << compiler::GetOpcodeString(inst->GetOpcode())
|
||||
<< " not yet implemented in RegEncoder";
|
||||
success_ = false;
|
||||
}
|
||||
|
||||
#include "compiler/optimizer/ir/visitor.inc"
|
||||
|
||||
private:
|
||||
void CalculateNumNeededTemps();
|
||||
void CalculateNumNeededTempsForInst(compiler::Inst *inst);
|
||||
void RenumberRegs(compiler::Register min_reg, compiler::Register delta);
|
||||
bool RenumberArgRegs();
|
||||
void InsertSpills();
|
||||
void InsertSpillsForInst(compiler::Inst *inst);
|
||||
void InsertSpillsForDynInputsInst(compiler::Inst *inst);
|
||||
size_t GetStartInputIndex(compiler::Inst *inst);
|
||||
|
||||
compiler::Register GetNumArgsFromGraph() const
|
||||
{
|
||||
auto adapter = GetGraph()->GetRuntime();
|
||||
auto method = GetGraph()->GetMethod();
|
||||
auto num_args = adapter->GetMethodTotalArgumentsCount(method);
|
||||
ASSERT(num_args <= compiler::VIRTUAL_FRAME_SIZE);
|
||||
return num_args;
|
||||
}
|
||||
|
||||
compiler::Register GetNumLocalsFromGraph() const
|
||||
{
|
||||
auto num_locals = GetGraph()->GetStackSlotsCount();
|
||||
ASSERT(num_locals <= compiler::VIRTUAL_FRAME_SIZE);
|
||||
return num_locals;
|
||||
}
|
||||
|
||||
compiler::Register GetNumRegs() const
|
||||
{
|
||||
auto num_regs = GetNumLocalsFromGraph() + GetNumArgsFromGraph();
|
||||
ASSERT(num_regs <= compiler::VIRTUAL_FRAME_SIZE);
|
||||
return num_regs;
|
||||
}
|
||||
|
||||
void SaveNumLocalsToGraph(uint32_t num_locals) const
|
||||
{
|
||||
ASSERT(num_locals <= compiler::VIRTUAL_FRAME_SIZE);
|
||||
GetGraph()->SetStackSlotsCount(num_locals);
|
||||
}
|
||||
|
||||
bool GetStatus() const
|
||||
{
|
||||
return success_;
|
||||
}
|
||||
|
||||
static void CallHelper(compiler::GraphVisitor *visitor, Inst *inst)
|
||||
{
|
||||
auto *re = static_cast<RegEncoder *>(visitor);
|
||||
re->Check4Width(inst);
|
||||
}
|
||||
|
||||
private:
|
||||
compiler::Register num_temps_ {0};
|
||||
RegEncoderState state_ {RegEncoderState::IDLE};
|
||||
compiler::Register num_max_range_input_ {0};
|
||||
compiler::Register range_temps_start_ {0};
|
||||
compiler::Register num_changed_width_ {0};
|
||||
|
||||
bool success_ {true};
|
||||
};
|
||||
} // namespace panda::bytecodeopt
|
||||
|
||||
#endif // PANDA_REG_ENCODER_H
|
459
static_core/bytecode_optimizer/runtime_adapter.h
Normal file
459
static_core/bytecode_optimizer/runtime_adapter.h
Normal file
@ -0,0 +1,459 @@
|
||||
/**
|
||||
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#ifndef PANDA_BYTECODE_OPTIMIZER_RUNTIME_ADAPTER_H_
|
||||
#define PANDA_BYTECODE_OPTIMIZER_RUNTIME_ADAPTER_H_
|
||||
|
||||
#include "compiler/optimizer/ir/runtime_interface.h"
|
||||
#include "libpandafile/bytecode_instruction.h"
|
||||
#include "libpandafile/class_data_accessor-inl.h"
|
||||
#include "libpandafile/code_data_accessor.h"
|
||||
#include "libpandafile/field_data_accessor.h"
|
||||
#include "libpandafile/file.h"
|
||||
#include "libpandafile/file_items.h"
|
||||
#include "libpandafile/method_data_accessor.h"
|
||||
#include "libpandafile/proto_data_accessor.h"
|
||||
#include "libpandafile/proto_data_accessor-inl.h"
|
||||
#include "libpandafile/type_helper.h"
|
||||
|
||||
namespace panda {
|
||||
using compiler::RuntimeInterface;
|
||||
|
||||
class BytecodeOptimizerRuntimeAdapter : public RuntimeInterface {
|
||||
public:
|
||||
explicit BytecodeOptimizerRuntimeAdapter(const panda_file::File &panda_file) : panda_file_(panda_file) {}
|
||||
~BytecodeOptimizerRuntimeAdapter() override = default;
|
||||
NO_COPY_SEMANTIC(BytecodeOptimizerRuntimeAdapter);
|
||||
NO_MOVE_SEMANTIC(BytecodeOptimizerRuntimeAdapter);
|
||||
|
||||
BinaryFilePtr GetBinaryFileForMethod([[maybe_unused]] MethodPtr method) const override
|
||||
{
|
||||
return const_cast<panda_file::File *>(&panda_file_);
|
||||
}
|
||||
|
||||
MethodId ResolveMethodIndex(MethodPtr parent_method, MethodIndex index) const override
|
||||
{
|
||||
return panda_file_.ResolveMethodIndex(MethodCast(parent_method), index).GetOffset();
|
||||
}
|
||||
|
||||
FieldId ResolveFieldIndex(MethodPtr parent_method, FieldIndex index) const override
|
||||
{
|
||||
return panda_file_.ResolveFieldIndex(MethodCast(parent_method), index).GetOffset();
|
||||
}
|
||||
|
||||
IdType ResolveTypeIndex(MethodPtr parent_method, TypeIndex index) const override
|
||||
{
|
||||
return panda_file_.ResolveClassIndex(MethodCast(parent_method), index).GetOffset();
|
||||
}
|
||||
|
||||
MethodPtr GetMethodById([[maybe_unused]] MethodPtr caller, MethodId id) const override
|
||||
{
|
||||
return reinterpret_cast<MethodPtr>(id);
|
||||
}
|
||||
|
||||
MethodId GetMethodId(MethodPtr method) const override
|
||||
{
|
||||
return static_cast<MethodId>(reinterpret_cast<uintptr_t>(method));
|
||||
}
|
||||
|
||||
compiler::DataType::Type GetMethodReturnType(MethodPtr method) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
|
||||
panda_file::ProtoDataAccessor pda(panda_file_, mda.GetProtoId());
|
||||
|
||||
return ToCompilerType(panda_file::GetEffectiveType(pda.GetReturnType()));
|
||||
}
|
||||
|
||||
IdType GetMethodReturnTypeId(MethodPtr method) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
|
||||
panda_file::ProtoDataAccessor pda(panda_file_, mda.GetProtoId());
|
||||
|
||||
return pda.GetReferenceType(0).GetOffset();
|
||||
}
|
||||
|
||||
compiler::DataType::Type GetMethodTotalArgumentType(MethodPtr method, size_t index) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
|
||||
|
||||
if (!mda.IsStatic()) {
|
||||
if (index == 0) {
|
||||
return ToCompilerType(
|
||||
panda_file::GetEffectiveType(panda_file::Type(panda_file::Type::TypeId::REFERENCE)));
|
||||
}
|
||||
--index;
|
||||
}
|
||||
|
||||
panda_file::ProtoDataAccessor pda(panda_file_, mda.GetProtoId());
|
||||
return ToCompilerType(panda_file::GetEffectiveType(pda.GetArgType(index)));
|
||||
}
|
||||
|
||||
compiler::DataType::Type GetMethodArgumentType([[maybe_unused]] MethodPtr caller, MethodId id,
|
||||
size_t index) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, panda_file::File::EntityId(id));
|
||||
panda_file::ProtoDataAccessor pda(panda_file_, mda.GetProtoId());
|
||||
|
||||
return ToCompilerType(panda_file::GetEffectiveType(pda.GetArgType(index)));
|
||||
}
|
||||
|
||||
size_t GetMethodTotalArgumentsCount(MethodPtr method) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
|
||||
|
||||
ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
|
||||
panda_file::CodeDataAccessor cda(panda_file_, mda.GetCodeId().value());
|
||||
|
||||
return cda.GetNumArgs();
|
||||
}
|
||||
|
||||
size_t GetMethodArgumentsCount([[maybe_unused]] MethodPtr caller, MethodId id) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, panda_file::File::EntityId(id));
|
||||
panda_file::ProtoDataAccessor pda(panda_file_, mda.GetProtoId());
|
||||
|
||||
return pda.GetNumArgs();
|
||||
}
|
||||
|
||||
compiler::DataType::Type GetMethodReturnType(MethodPtr caller, MethodId id) const override
|
||||
{
|
||||
return GetMethodReturnType(GetMethodById(caller, id));
|
||||
}
|
||||
|
||||
size_t GetMethodRegistersCount(MethodPtr method) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
|
||||
|
||||
ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
|
||||
panda_file::CodeDataAccessor cda(panda_file_, mda.GetCodeId().value());
|
||||
|
||||
return cda.GetNumVregs();
|
||||
}
|
||||
|
||||
const uint8_t *GetMethodCode(MethodPtr method) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
|
||||
|
||||
ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
|
||||
panda_file::CodeDataAccessor cda(panda_file_, mda.GetCodeId().value());
|
||||
|
||||
return cda.GetInstructions();
|
||||
}
|
||||
|
||||
size_t GetMethodCodeSize(MethodPtr method) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
|
||||
|
||||
ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
|
||||
panda_file::CodeDataAccessor cda(panda_file_, mda.GetCodeId().value());
|
||||
|
||||
return cda.GetCodeSize();
|
||||
}
|
||||
|
||||
SourceLanguage GetMethodSourceLanguage(MethodPtr method) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
|
||||
|
||||
ASSERT(!mda.IsExternal() && !mda.IsAbstract() && !mda.IsNative());
|
||||
|
||||
auto source_lang = mda.GetSourceLang();
|
||||
ASSERT(source_lang.has_value());
|
||||
|
||||
return static_cast<SourceLanguage>(source_lang.value());
|
||||
}
|
||||
|
||||
size_t GetClassIdForField([[maybe_unused]] MethodPtr method, size_t field_id) const override
|
||||
{
|
||||
panda_file::FieldDataAccessor fda(panda_file_, panda_file::File::EntityId(field_id));
|
||||
|
||||
return static_cast<size_t>(fda.GetClassId().GetOffset());
|
||||
}
|
||||
|
||||
ClassPtr GetClassForField(FieldPtr field) const override
|
||||
{
|
||||
panda_file::FieldDataAccessor fda(panda_file_, FieldCast(field));
|
||||
|
||||
return reinterpret_cast<ClassPtr>(fda.GetClassId().GetOffset());
|
||||
}
|
||||
|
||||
size_t GetClassIdForMethod(MethodPtr method) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
|
||||
|
||||
return static_cast<size_t>(mda.GetClassId().GetOffset());
|
||||
}
|
||||
|
||||
size_t GetClassIdForMethod([[maybe_unused]] MethodPtr caller, size_t method_id) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, panda_file::File::EntityId(method_id));
|
||||
|
||||
return static_cast<size_t>(mda.GetClassId().GetOffset());
|
||||
}
|
||||
|
||||
bool IsMethodExternal([[maybe_unused]] MethodPtr caller, MethodPtr callee) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(callee));
|
||||
|
||||
return mda.IsExternal();
|
||||
}
|
||||
|
||||
bool IsMethodIntrinsic([[maybe_unused]] MethodPtr method) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsMethodIntrinsic([[maybe_unused]] MethodPtr caller, [[maybe_unused]] MethodId id) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsMethodStatic(MethodPtr method) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
|
||||
|
||||
return mda.IsStatic();
|
||||
}
|
||||
|
||||
bool IsMethodStatic([[maybe_unused]] MethodPtr caller, MethodId id) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, panda_file::File::EntityId(id));
|
||||
|
||||
return mda.IsStatic();
|
||||
}
|
||||
|
||||
// return true if the method is Native with exception
|
||||
bool HasNativeException([[maybe_unused]] MethodPtr method) const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string GetClassNameFromMethod(MethodPtr method) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
|
||||
|
||||
auto string_data = panda_file_.GetStringData(mda.GetClassId());
|
||||
|
||||
return std::string(reinterpret_cast<const char *>(string_data.data));
|
||||
}
|
||||
|
||||
std::string GetClassName(ClassPtr cls) const override
|
||||
{
|
||||
auto string_data = panda_file_.GetStringData(ClassCast(cls));
|
||||
|
||||
return std::string(reinterpret_cast<const char *>(string_data.data));
|
||||
}
|
||||
|
||||
std::string GetMethodName(MethodPtr method) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
|
||||
|
||||
auto string_data = panda_file_.GetStringData(mda.GetNameId());
|
||||
|
||||
return std::string(reinterpret_cast<const char *>(string_data.data));
|
||||
}
|
||||
|
||||
bool IsConstructor(MethodPtr method, SourceLanguage lang) override
|
||||
{
|
||||
return GetMethodName(method) == panda_file::GetCtorName(lang);
|
||||
}
|
||||
|
||||
std::string GetMethodFullName(MethodPtr method, bool /* with_signature */) const override
|
||||
{
|
||||
auto class_name = GetClassNameFromMethod(method);
|
||||
auto method_name = GetMethodName(method);
|
||||
|
||||
return class_name + "::" + method_name;
|
||||
}
|
||||
|
||||
ClassPtr GetClass(MethodPtr method) const override
|
||||
{
|
||||
panda_file::MethodDataAccessor mda(panda_file_, MethodCast(method));
|
||||
|
||||
return reinterpret_cast<ClassPtr>(mda.GetClassId().GetOffset());
|
||||
}
|
||||
|
||||
std::string GetBytecodeString(MethodPtr method, uintptr_t pc) const override
|
||||
{
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
|
||||
BytecodeInstruction inst(GetMethodCode(method) + pc);
|
||||
std::stringstream ss;
|
||||
|
||||
ss << inst;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
bool IsArrayClass([[maybe_unused]] MethodPtr method, IdType id) const override
|
||||
{
|
||||
panda_file::File::EntityId cid(id);
|
||||
|
||||
return panda_file::IsArrayDescriptor(panda_file_.GetStringData(cid).data);
|
||||
}
|
||||
|
||||
FieldPtr ResolveField([[maybe_unused]] MethodPtr method, size_t id, [[maybe_unused]] bool allow_external,
|
||||
uint32_t * /* class_id */) override
|
||||
{
|
||||
return reinterpret_cast<FieldPtr>(id);
|
||||
}
|
||||
|
||||
compiler::DataType::Type GetFieldType(FieldPtr field) const override
|
||||
{
|
||||
panda_file::FieldDataAccessor fda(panda_file_, FieldCast(field));
|
||||
|
||||
return ToCompilerType(panda_file::Type::GetTypeFromFieldEncoding(fda.GetType()));
|
||||
}
|
||||
|
||||
compiler::DataType::Type GetFieldTypeById([[maybe_unused]] MethodPtr parent_method, IdType id) const override
|
||||
{
|
||||
panda_file::FieldDataAccessor fda(panda_file_, panda_file::File::EntityId(id));
|
||||
|
||||
return ToCompilerType(panda_file::Type::GetTypeFromFieldEncoding(fda.GetType()));
|
||||
}
|
||||
|
||||
IdType GetFieldValueTypeId([[maybe_unused]] MethodPtr method, IdType id) const override
|
||||
{
|
||||
auto type_id = panda_file::FieldDataAccessor::GetTypeId(panda_file_, panda_file::File::EntityId(id));
|
||||
return type_id.GetOffset();
|
||||
}
|
||||
|
||||
bool IsFieldVolatile(FieldPtr field) const override
|
||||
{
|
||||
panda_file::FieldDataAccessor fda(panda_file_, FieldCast(field));
|
||||
|
||||
if (!fda.IsExternal()) {
|
||||
return fda.IsVolatile();
|
||||
}
|
||||
|
||||
auto field_id = panda_file::File::EntityId();
|
||||
|
||||
if (panda_file_.IsExternal(fda.GetClassId())) {
|
||||
// If the field is external and class of the field is also external
|
||||
// assume that field is volatile
|
||||
return true;
|
||||
}
|
||||
|
||||
auto class_id = panda_file::ClassDataAccessor(panda_file_, fda.GetClassId()).GetSuperClassId();
|
||||
#ifndef NDEBUG
|
||||
auto visited_classes = std::unordered_set<panda_file::File::EntityId> {class_id};
|
||||
#endif
|
||||
while (class_id.IsValid() && !panda_file_.IsExternal(class_id)) {
|
||||
auto cda = panda_file::ClassDataAccessor(panda_file_, class_id);
|
||||
cda.EnumerateFields([&field_id, &fda](panda_file::FieldDataAccessor &field_data_accessor) {
|
||||
auto &pf = fda.GetPandaFile();
|
||||
auto field_type = panda_file::Type::GetTypeFromFieldEncoding(fda.GetType());
|
||||
if (fda.GetType() != field_data_accessor.GetType()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pf.GetStringData(fda.GetNameId()) != pf.GetStringData(field_data_accessor.GetNameId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (field_type.IsReference()) {
|
||||
if (pf.GetStringData(panda_file::File::EntityId(fda.GetType())) !=
|
||||
pf.GetStringData(panda_file::File::EntityId(field_data_accessor.GetType()))) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
field_id = field_data_accessor.GetFieldId();
|
||||
});
|
||||
|
||||
class_id = cda.GetSuperClassId();
|
||||
#ifndef NDEBUG
|
||||
ASSERT_PRINT(visited_classes.count(class_id) == 0, "Class hierarchy is incorrect");
|
||||
visited_classes.insert(class_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!field_id.IsValid()) {
|
||||
// If we cannot find field (for example it's in the class that located in other panda file)
|
||||
// assume that field is volatile
|
||||
return true;
|
||||
}
|
||||
ASSERT(field_id.IsValid());
|
||||
panda_file::FieldDataAccessor field_da(panda_file_, field_id);
|
||||
return field_da.IsVolatile();
|
||||
}
|
||||
|
||||
ClassPtr ResolveType([[maybe_unused]] MethodPtr method, size_t id) const override
|
||||
{
|
||||
return reinterpret_cast<ClassPtr>(id);
|
||||
}
|
||||
|
||||
std::string GetFieldName(FieldPtr field) const override
|
||||
{
|
||||
panda_file::FieldDataAccessor fda(panda_file_, FieldCast(field));
|
||||
auto string_data = panda_file_.GetStringData(fda.GetNameId());
|
||||
return utf::Mutf8AsCString(string_data.data);
|
||||
}
|
||||
|
||||
private:
|
||||
static compiler::DataType::Type ToCompilerType(panda_file::Type type)
|
||||
{
|
||||
switch (type.GetId()) {
|
||||
case panda_file::Type::TypeId::VOID:
|
||||
return compiler::DataType::VOID;
|
||||
case panda_file::Type::TypeId::U1:
|
||||
return compiler::DataType::BOOL;
|
||||
case panda_file::Type::TypeId::I8:
|
||||
return compiler::DataType::INT8;
|
||||
case panda_file::Type::TypeId::U8:
|
||||
return compiler::DataType::UINT8;
|
||||
case panda_file::Type::TypeId::I16:
|
||||
return compiler::DataType::INT16;
|
||||
case panda_file::Type::TypeId::U16:
|
||||
return compiler::DataType::UINT16;
|
||||
case panda_file::Type::TypeId::I32:
|
||||
return compiler::DataType::INT32;
|
||||
case panda_file::Type::TypeId::U32:
|
||||
return compiler::DataType::UINT32;
|
||||
case panda_file::Type::TypeId::I64:
|
||||
return compiler::DataType::INT64;
|
||||
case panda_file::Type::TypeId::U64:
|
||||
return compiler::DataType::UINT64;
|
||||
case panda_file::Type::TypeId::F32:
|
||||
return compiler::DataType::FLOAT32;
|
||||
case panda_file::Type::TypeId::F64:
|
||||
return compiler::DataType::FLOAT64;
|
||||
case panda_file::Type::TypeId::REFERENCE:
|
||||
return compiler::DataType::REFERENCE;
|
||||
case panda_file::Type::TypeId::TAGGED:
|
||||
case panda_file::Type::TypeId::INVALID:
|
||||
return compiler::DataType::ANY;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
static panda_file::File::EntityId MethodCast(RuntimeInterface::MethodPtr method)
|
||||
{
|
||||
return panda_file::File::EntityId(reinterpret_cast<uintptr_t>(method));
|
||||
}
|
||||
|
||||
static panda_file::File::EntityId ClassCast(RuntimeInterface::ClassPtr cls)
|
||||
{
|
||||
return panda_file::File::EntityId(reinterpret_cast<uintptr_t>(cls));
|
||||
}
|
||||
|
||||
static panda_file::File::EntityId FieldCast(RuntimeInterface::FieldPtr field)
|
||||
{
|
||||
return panda_file::File::EntityId(reinterpret_cast<uintptr_t>(field));
|
||||
}
|
||||
|
||||
const panda_file::File &panda_file_;
|
||||
};
|
||||
} // namespace panda
|
||||
|
||||
#endif // PANDA_BYTECODE_OPTIMIZER_RUNTIME_ADAPTER_H_
|
@ -0,0 +1,67 @@
|
||||
# Copyright (c) 2021-2022 Huawei Device Co., Ltd.
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
|
||||
set(CODEGEN_VISITORS_INC ${PANDA_BINARY_ROOT}/bytecode_optimizer/generated/codegen_visitors.inc)
|
||||
panda_gen_file(
|
||||
DATAFILE ${GEN_PLUGIN_OPTIONS_YAML}
|
||||
TEMPLATE ${PANDA_ROOT}/bytecode_optimizer/templates/codegen_visitors.inc.erb
|
||||
REQUIRES ${PANDA_ROOT}/templates/plugin_options.rb
|
||||
EXTRA_DEPENDENCIES plugin_options_merge
|
||||
OUTPUTFILE ${CODEGEN_VISITORS_INC}
|
||||
)
|
||||
|
||||
add_custom_target(bytecode_optimizer_codegen_visitors_inc DEPENDS
|
||||
plugin_options_gen
|
||||
${CODEGEN_VISITORS_INC}
|
||||
)
|
||||
|
||||
set(REG_ENCODER_VISITORS_INC ${PANDA_BINARY_ROOT}/bytecode_optimizer/generated/reg_encoder_visitors.inc)
|
||||
panda_gen_file(
|
||||
DATAFILE ${GEN_PLUGIN_OPTIONS_YAML}
|
||||
TEMPLATE ${PANDA_ROOT}/bytecode_optimizer/templates/reg_encoder_visitors.inc.erb
|
||||
REQUIRES ${PANDA_ROOT}/templates/plugin_options.rb
|
||||
EXTRA_DEPENDENCIES plugin_options_merge
|
||||
OUTPUTFILE ${REG_ENCODER_VISITORS_INC}
|
||||
)
|
||||
|
||||
add_custom_target(bytecode_optimizer_reg_encoder_visitors_inc DEPENDS
|
||||
plugin_options_gen
|
||||
${REG_ENCODER_VISITORS_INC}
|
||||
)
|
||||
|
||||
set(CODEGEN_INTRINSICS_CPP ${PANDA_BINARY_ROOT}/bytecode_optimizer/generated/codegen_intrinsics.cpp)
|
||||
panda_gen_file(
|
||||
DATAFILE ${GEN_PLUGIN_OPTIONS_YAML}
|
||||
TEMPLATE ${PANDA_ROOT}/bytecode_optimizer/templates/codegen_intrinsics.cpp.erb
|
||||
REQUIRES ${PANDA_ROOT}/templates/plugin_options.rb
|
||||
EXTRA_DEPENDENCIES plugin_options_merge
|
||||
OUTPUTFILE ${CODEGEN_INTRINSICS_CPP}
|
||||
)
|
||||
|
||||
add_custom_target(bytecode_optimizer_codegen_intrinsics_cpp DEPENDS
|
||||
plugin_options_gen
|
||||
${CODEGEN_INTRINSICS_CPP}
|
||||
)
|
||||
|
||||
add_dependencies(arkbytecodeopt_obj
|
||||
bytecode_optimizer_codegen_visitors_inc
|
||||
bytecode_optimizer_reg_encoder_visitors_inc
|
||||
bytecode_optimizer_codegen_intrinsics_cpp
|
||||
)
|
||||
|
||||
add_dependencies(panda_gen_files
|
||||
bytecode_optimizer_codegen_visitors_inc
|
||||
bytecode_optimizer_reg_encoder_visitors_inc
|
||||
bytecode_optimizer_codegen_intrinsics_cpp
|
||||
)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user