mirror of
https://github.com/lifting-bits/remill
synced 2026-06-21 13:56:07 +00:00
Running clang-format on files with some additional custom scripts for… (#444)
* Running clang-format on files with some additional custom scripts for my style * Fix missing unique_ptr in remill/BC/Optimizer.h * Fixes and selective disabling of clang-format
This commit is contained in:
+61
-88
@@ -1,96 +1,69 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: Google
|
||||
AccessModifierOffset: -1
|
||||
BasedOnStyle: Google
|
||||
AccessModifierOffset: '-1'
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlinesLeft: true
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlignConsecutiveMacros: 'false'
|
||||
AlignConsecutiveAssignments: 'false'
|
||||
AlignConsecutiveDeclarations: 'false'
|
||||
AlignEscapedNewlines: DontAlign
|
||||
AlignOperands: 'true'
|
||||
AlignTrailingComments: 'false'
|
||||
AllowAllArgumentsOnNextLine: 'true'
|
||||
AllowAllConstructorInitializersOnNextLine: 'false'
|
||||
AllowAllParametersOfDeclarationOnNextLine: 'true'
|
||||
AllowShortBlocksOnASingleLine: 'false'
|
||||
AllowShortCaseLabelsOnASingleLine: 'true'
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: 'false'
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
AlwaysBreakTemplateDeclarations: 'Yes'
|
||||
BinPackParameters: 'true'
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: true
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
|
||||
IncludeCategories:
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentCaseLabels: true
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
BreakBeforeBraces: Custom
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakStringLiterals: 'false'
|
||||
ColumnLimit: '80'
|
||||
CompactNamespaces: 'false'
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: 'true'
|
||||
ConstructorInitializerIndentWidth: '4'
|
||||
ContinuationIndentWidth: '4'
|
||||
Cpp11BracedListStyle: 'true'
|
||||
DerivePointerAlignment: 'false'
|
||||
FixNamespaceComments: 'true'
|
||||
IncludeBlocks: Regroup
|
||||
IndentCaseLabels: 'true'
|
||||
IndentPPDirectives: AfterHash
|
||||
IndentWidth: '2'
|
||||
IndentWrappedFunctionNames: 'false'
|
||||
KeepEmptyLinesAtTheStartOfBlocks: 'true'
|
||||
Language: Cpp
|
||||
MaxEmptyLinesToKeep: '2'
|
||||
NamespaceIndentation: None
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: false
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
PointerAlignment: Right
|
||||
ReflowComments: 'false'
|
||||
SortIncludes: 'true'
|
||||
SortUsingDeclarations: 'true'
|
||||
SpaceAfterCStyleCast: 'true'
|
||||
SpaceAfterLogicalNot: 'false'
|
||||
SpaceAfterTemplateKeyword: 'true'
|
||||
SpaceBeforeAssignmentOperators: 'true'
|
||||
SpaceBeforeCtorInitializerColon: 'true'
|
||||
SpaceBeforeInheritanceColon: 'true'
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
TabWidth: 2
|
||||
SpaceBeforeRangeBasedForLoopColon: 'true'
|
||||
SpaceInEmptyParentheses: 'false'
|
||||
SpacesBeforeTrailingComments: '2'
|
||||
SpacesInAngles: 'false'
|
||||
SpacesInCStyleCastParentheses: 'false'
|
||||
SpacesInContainerLiterals: 'false'
|
||||
SpacesInParentheses: 'false'
|
||||
SpacesInSquareBrackets: 'false'
|
||||
Standard: Cpp11
|
||||
TabWidth: '2'
|
||||
UseTab: Never
|
||||
...
|
||||
PenaltyReturnTypeOnItsOwnLine: '40'
|
||||
|
||||
...
|
||||
|
||||
+176
-237
File diff suppressed because it is too large
Load Diff
@@ -2515,7 +2515,8 @@ bool TryDecodeFMIN_D_FLOATDP2(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeUMLSL_ASIMDELEM_L(const InstData &data, Instruction &inst);
|
||||
|
||||
// FMAXNM <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
bool TryDecodeFMAXNM_ASIMDSAMEFP16_ONLY(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFMAXNM_ASIMDSAMEFP16_ONLY(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// FMAXNM <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
bool TryDecodeFMAXNM_ASIMDSAME_ONLY(const InstData &data, Instruction &inst);
|
||||
@@ -3199,7 +3200,8 @@ bool TryDecodeSTEORH_32S_MEMOP(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeSTEORLH_32S_MEMOP(const InstData &data, Instruction &inst);
|
||||
|
||||
// FMINNMP <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
bool TryDecodeFMINNMP_ASIMDSAMEFP16_ONLY(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFMINNMP_ASIMDSAMEFP16_ONLY(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// FMINNMP <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
bool TryDecodeFMINNMP_ASIMDSAME_ONLY(const InstData &data, Instruction &inst);
|
||||
@@ -3340,7 +3342,8 @@ bool TryDecodeASR_ASRV_32_DP_2SRC(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeASR_ASRV_64_DP_2SRC(const InstData &data, Instruction &inst);
|
||||
|
||||
// UMULL <Xd>, <Wn>, <Wm>
|
||||
bool TryDecodeUMULL_UMADDL_64WA_DP_3SRC(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeUMULL_UMADDL_64WA_DP_3SRC(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// FCMGT <Hd>, <Hn>, <Hm>
|
||||
bool TryDecodeFCMGT_ASISDSAMEFP16_ONLY(const InstData &data, Instruction &inst);
|
||||
@@ -4111,7 +4114,8 @@ bool TryDecodeADD_64_ADDSUB_EXT(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFMAXNMP_ASISDPAIR_ONLY_H(const InstData &data, Instruction &inst);
|
||||
|
||||
// FMAXNMP <V><d>, <Vn>.<T>
|
||||
bool TryDecodeFMAXNMP_ASISDPAIR_ONLY_SD(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFMAXNMP_ASISDPAIR_ONLY_SD(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// BICS <Wd>, <Wn>, <Wm>{, <shift> #<amount>}
|
||||
bool TryDecodeBICS_32_LOG_SHIFT(const InstData &data, Instruction &inst);
|
||||
@@ -4168,10 +4172,12 @@ bool TryDecodeFMSUB_S_FLOATDP3(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFMSUB_D_FLOATDP3(const InstData &data, Instruction &inst);
|
||||
|
||||
// NGCS <Wd>, <Wm>
|
||||
bool TryDecodeNGCS_SBCS_32_ADDSUB_CARRY(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeNGCS_SBCS_32_ADDSUB_CARRY(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// NGCS <Xd>, <Xm>
|
||||
bool TryDecodeNGCS_SBCS_64_ADDSUB_CARRY(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeNGCS_SBCS_64_ADDSUB_CARRY(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// STR <Wt>, [<Xn|SP>], #<simm>
|
||||
bool TryDecodeSTR_32_LDST_IMMPOST(const InstData &data, Instruction &inst);
|
||||
@@ -4264,13 +4270,15 @@ bool TryDecodeRBIT_32_DP_1SRC(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeRBIT_64_DP_1SRC(const InstData &data, Instruction &inst);
|
||||
|
||||
// SMNEGL <Xd>, <Wn>, <Wm>
|
||||
bool TryDecodeSMNEGL_SMSUBL_64WA_DP_3SRC(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeSMNEGL_SMSUBL_64WA_DP_3SRC(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// MOV <V><d>, <Vn>.<T>[<index>]
|
||||
bool TryDecodeMOV_DUP_ASISDONE_ONLY(const InstData &data, Instruction &inst);
|
||||
|
||||
// SMULL <Xd>, <Wn>, <Wm>
|
||||
bool TryDecodeSMULL_SMADDL_64WA_DP_3SRC(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeSMULL_SMADDL_64WA_DP_3SRC(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// ZIP2 <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
bool TryDecodeZIP2_ASIMDPERM_ONLY(const InstData &data, Instruction &inst);
|
||||
@@ -4333,7 +4341,8 @@ bool TryDecodeFCVTMU_ASIMDMISCFP16_R(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFCVTMU_ASIMDMISC_R(const InstData &data, Instruction &inst);
|
||||
|
||||
// FMAXNMP <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
bool TryDecodeFMAXNMP_ASIMDSAMEFP16_ONLY(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFMAXNMP_ASIMDSAMEFP16_ONLY(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// FMAXNMP <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
bool TryDecodeFMAXNMP_ASIMDSAME_ONLY(const InstData &data, Instruction &inst);
|
||||
@@ -4408,13 +4417,15 @@ bool TryDecodeLDSET_64_MEMOP(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeLDSETL_64_MEMOP(const InstData &data, Instruction &inst);
|
||||
|
||||
// FRECPS <Hd>, <Hn>, <Hm>
|
||||
bool TryDecodeFRECPS_ASISDSAMEFP16_ONLY(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFRECPS_ASISDSAMEFP16_ONLY(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// FRECPS <V><d>, <V><n>, <V><m>
|
||||
bool TryDecodeFRECPS_ASISDSAME_ONLY(const InstData &data, Instruction &inst);
|
||||
|
||||
// FRECPS <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
bool TryDecodeFRECPS_ASIMDSAMEFP16_ONLY(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFRECPS_ASIMDSAMEFP16_ONLY(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// FRECPS <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
bool TryDecodeFRECPS_ASIMDSAME_ONLY(const InstData &data, Instruction &inst);
|
||||
@@ -4561,13 +4572,15 @@ bool TryDecodeFCMPE_D_FLOATCMP(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFCMPE_DZ_FLOATCMP(const InstData &data, Instruction &inst);
|
||||
|
||||
// FRSQRTS <Hd>, <Hn>, <Hm>
|
||||
bool TryDecodeFRSQRTS_ASISDSAMEFP16_ONLY(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFRSQRTS_ASISDSAMEFP16_ONLY(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// FRSQRTS <V><d>, <V><n>, <V><m>
|
||||
bool TryDecodeFRSQRTS_ASISDSAME_ONLY(const InstData &data, Instruction &inst);
|
||||
|
||||
// FRSQRTS <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
bool TryDecodeFRSQRTS_ASIMDSAMEFP16_ONLY(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFRSQRTS_ASIMDSAMEFP16_ONLY(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// FRSQRTS <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
bool TryDecodeFRSQRTS_ASIMDSAME_ONLY(const InstData &data, Instruction &inst);
|
||||
@@ -5209,7 +5222,8 @@ bool TryDecodeSADDW_ASIMDDIFF_W(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeSADDLP_ASIMDMISC_P(const InstData &data, Instruction &inst);
|
||||
|
||||
// UMNEGL <Xd>, <Wn>, <Wm>
|
||||
bool TryDecodeUMNEGL_UMSUBL_64WA_DP_3SRC(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeUMNEGL_UMSUBL_64WA_DP_3SRC(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// ST2 { <Vt>.<T>, <Vt2>.<T> }, [<Xn|SP>]
|
||||
bool TryDecodeST2_ASISDLSE_R2(const InstData &data, Instruction &inst);
|
||||
@@ -5422,10 +5436,12 @@ bool TryDecodeCASB_C32_LDSTEXCL(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeCASLB_C32_LDSTEXCL(const InstData &data, Instruction &inst);
|
||||
|
||||
// NEGS <Wd>, <Wm>{, <shift> #<amount>}
|
||||
bool TryDecodeNEGS_SUBS_32_ADDSUB_SHIFT(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeNEGS_SUBS_32_ADDSUB_SHIFT(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// NEGS <Xd>, <Xm>{, <shift> #<amount>}
|
||||
bool TryDecodeNEGS_SUBS_64_ADDSUB_SHIFT(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeNEGS_SUBS_64_ADDSUB_SHIFT(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// LDSMAXAH <Ws>, <Wt>, [<Xn|SP>]
|
||||
bool TryDecodeLDSMAXAH_32_MEMOP(const InstData &data, Instruction &inst);
|
||||
@@ -6211,7 +6227,8 @@ bool TryDecodeUQSHL_ASIMDSHF_R(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFMINNMP_ASISDPAIR_ONLY_H(const InstData &data, Instruction &inst);
|
||||
|
||||
// FMINNMP <V><d>, <Vn>.<T>
|
||||
bool TryDecodeFMINNMP_ASISDPAIR_ONLY_SD(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFMINNMP_ASISDPAIR_ONLY_SD(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// UMADDL <Xd>, <Wn>, <Wm>, <Xa>
|
||||
bool TryDecodeUMADDL_64WA_DP_3SRC(const InstData &data, Instruction &inst);
|
||||
@@ -6700,7 +6717,8 @@ bool TryDecodeCMN_ADDS_32S_ADDSUB_EXT(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeCMN_ADDS_64S_ADDSUB_EXT(const InstData &data, Instruction &inst);
|
||||
|
||||
// FMINNM <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
bool TryDecodeFMINNM_ASIMDSAMEFP16_ONLY(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeFMINNM_ASIMDSAMEFP16_ONLY(const InstData &data,
|
||||
Instruction &inst);
|
||||
|
||||
// FMINNM <Vd>.<T>, <Vn>.<T>, <Vm>.<T>
|
||||
bool TryDecodeFMINNM_ASIMDSAME_ONLY(const InstData &data, Instruction &inst);
|
||||
@@ -7081,7 +7099,6 @@ bool TryDecodeLDCLRB_32_MEMOP(const InstData &data, Instruction &inst);
|
||||
bool TryDecodeLDCLRLB_32_MEMOP(const InstData &data, Instruction &inst);
|
||||
|
||||
|
||||
|
||||
const char *InstNameToString(InstName iclass);
|
||||
const char *InstFormToString(InstForm iform);
|
||||
|
||||
|
||||
+2086
-784
File diff suppressed because it is too large
Load Diff
@@ -18,8 +18,8 @@
|
||||
#include <bitset>
|
||||
#include <cmath>
|
||||
|
||||
#include "remill/Arch/Float.h"
|
||||
#include "remill/Arch/AArch64/Runtime/State.h"
|
||||
#include "remill/Arch/Float.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
||||
@@ -18,12 +18,14 @@
|
||||
#include <bitset>
|
||||
#include <cmath>
|
||||
|
||||
// clang-format off
|
||||
#include "remill/Arch/Float.h"
|
||||
#include "remill/Arch/Runtime/Intrinsics.h"
|
||||
#include "remill/Arch/Runtime/Operators.h"
|
||||
#include "remill/Arch/AArch64/Runtime/State.h"
|
||||
#include "remill/Arch/AArch64/Runtime/Operators.h"
|
||||
#include "remill/Arch/AArch64/Runtime/Types.h"
|
||||
#include "remill/Arch/AArch64/Runtime/Operators.h"
|
||||
// clang-format on
|
||||
|
||||
#define REG_PC state.gpr.pc.qword
|
||||
#define REG_SP state.gpr.sp.qword
|
||||
@@ -80,10 +82,11 @@
|
||||
#define HYPER_CALL_VECTOR state.hyper_call_vector
|
||||
|
||||
namespace {
|
||||
|
||||
// Takes the place of an unsupported instruction.
|
||||
DEF_SEM(HandleUnsupported) {
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAArch64EmulateInstruction);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kAArch64EmulateInstruction);
|
||||
}
|
||||
|
||||
// Takes the place of an invalid instruction.
|
||||
@@ -98,17 +101,19 @@ DEF_SEM(HandleInvalidInstruction) {
|
||||
DEF_ISEL(UNSUPPORTED_INSTRUCTION) = HandleUnsupported;
|
||||
DEF_ISEL(INVALID_INSTRUCTION) = HandleInvalidInstruction;
|
||||
|
||||
// clang-format off
|
||||
#include "remill/Arch/AArch64/Semantics/FLAGS.cpp"
|
||||
|
||||
#include "remill/Arch/AArch64/Semantics/BINARY.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/BITBYTE.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/BRANCH.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/CALL_RET.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/COND.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/CONVERT.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/DATAXFER.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/LOGICAL.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/MISC.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/SHIFT.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/SIMD.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/COND.cpp"
|
||||
#include "remill/Arch/AArch64/Semantics/SYSTEM.cpp"
|
||||
// clang-format on
|
||||
|
||||
@@ -37,6 +37,7 @@ static_assert(0 == __builtin_offsetof(Reg, qword),
|
||||
"Invalid packing of `Reg::qword`.");
|
||||
|
||||
struct alignas(8) GPR final {
|
||||
|
||||
// Prevents LLVM from casting a `GPR` into an `i64` to access `X0`.
|
||||
volatile uint64_t _0;
|
||||
Reg x0;
|
||||
@@ -114,6 +115,7 @@ static_assert(528 == sizeof(GPR), "Invalid structure packing of `GPR`.");
|
||||
union PSTATE final {
|
||||
uint64_t flat;
|
||||
struct {
|
||||
|
||||
// Bit 0.
|
||||
uint64_t N : 1; // Negative condition flag.
|
||||
uint64_t Z : 1; // Zero condition flag.
|
||||
@@ -269,9 +271,7 @@ struct alignas(8) SR final {
|
||||
|
||||
static_assert(56 == sizeof(SR), "Invalid packing of `struct SR`.");
|
||||
|
||||
enum : size_t {
|
||||
kNumVecRegisters = 32
|
||||
};
|
||||
enum : size_t { kNumVecRegisters = 32 };
|
||||
|
||||
struct alignas(16) SIMD {
|
||||
vec128_t v[kNumVecRegisters];
|
||||
|
||||
@@ -333,8 +333,10 @@ DEF_SEM(FDIV_Scalar64, V128W dst, V64 src1, V64 src2) {
|
||||
|
||||
template <typename S>
|
||||
void FCompare(State &state, S val1, S val2, bool signal = true) {
|
||||
|
||||
// Set flags for operand == NAN
|
||||
if (std::isnan(val1) || std::isnan(val2)) {
|
||||
|
||||
// result = '0011';
|
||||
FLAG_N = 0;
|
||||
FLAG_Z = 0;
|
||||
@@ -348,6 +350,7 @@ void FCompare(State &state, S val1, S val2, bool signal = true) {
|
||||
// Regular float compare
|
||||
} else {
|
||||
if (FCmpEq(val1, val2)) {
|
||||
|
||||
// result = '0110';
|
||||
FLAG_N = 0;
|
||||
FLAG_Z = 1;
|
||||
@@ -355,6 +358,7 @@ void FCompare(State &state, S val1, S val2, bool signal = true) {
|
||||
FLAG_V = 0;
|
||||
|
||||
} else if (FCmpLt(val1, val2)) {
|
||||
|
||||
// result = '1000';
|
||||
FLAG_N = 1;
|
||||
FLAG_Z = 0;
|
||||
@@ -362,6 +366,7 @@ void FCompare(State &state, S val1, S val2, bool signal = true) {
|
||||
FLAG_V = 0;
|
||||
|
||||
} else { // FCmpGt(val1, val2)
|
||||
|
||||
// result = '0010';
|
||||
FLAG_N = 0;
|
||||
FLAG_Z = 0;
|
||||
@@ -487,4 +492,3 @@ DEF_ISEL(FCMPE_D_FLOATCMP) = FCMPE_D;
|
||||
DEF_ISEL(FCMPE_DZ_FLOATCMP) = FCMPE_DZ;
|
||||
DEF_ISEL(FCMP_D_FLOATCMP) = FCMP_D;
|
||||
DEF_ISEL(FCMP_DZ_FLOATCMP) = FCMP_DZ;
|
||||
|
||||
|
||||
@@ -114,8 +114,7 @@ namespace {
|
||||
DEF_SEM(REV16_32, R32W dst, R32 src) {
|
||||
vec32_t v = {};
|
||||
v.dwords.elems[0] = Read(src);
|
||||
_Pragma("unroll")
|
||||
for (auto &word : v.words.elems) {
|
||||
_Pragma("unroll") for (auto &word : v.words.elems) {
|
||||
word = __builtin_bswap16(word);
|
||||
}
|
||||
WriteZExt(dst, v.dwords.elems[0]);
|
||||
@@ -125,8 +124,7 @@ DEF_SEM(REV16_32, R32W dst, R32 src) {
|
||||
DEF_SEM(REV16_64, R64W dst, R64 src) {
|
||||
vec64_t v = {};
|
||||
v.qwords.elems[0] = Read(src);
|
||||
_Pragma("unroll")
|
||||
for (auto &word : v.words.elems) {
|
||||
_Pragma("unroll") for (auto &word : v.words.elems) {
|
||||
word = __builtin_bswap16(word);
|
||||
}
|
||||
Write(dst, v.qwords.elems[0]);
|
||||
@@ -141,8 +139,7 @@ DEF_SEM(REV32_32, R32W dst, R32 src) {
|
||||
DEF_SEM(REV32_64, R64W dst, R64 src) {
|
||||
vec64_t v = {};
|
||||
v.qwords.elems[0] = Read(src);
|
||||
_Pragma("unroll")
|
||||
for (auto &dword : v.dwords.elems) {
|
||||
_Pragma("unroll") for (auto &dword : v.dwords.elems) {
|
||||
dword = __builtin_bswap32(dword);
|
||||
}
|
||||
Write(dst, v.qwords.elems[0]);
|
||||
@@ -157,8 +154,7 @@ DEF_SEM(REV64, R64W dst, R64 src) {
|
||||
template <typename T, size_t n>
|
||||
ALWAYS_INLINE static T ReverseBits(T v) {
|
||||
T rv = 0;
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < n; ++i, v >>= 1) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < n; ++i, v >>= 1) {
|
||||
rv = (rv << T(1)) | (v & T(1));
|
||||
}
|
||||
return rv;
|
||||
|
||||
@@ -217,4 +217,3 @@ DEF_ISEL(TBZ_ONLY_TESTBRANCH_64) = TBZ<R64>;
|
||||
DEF_ISEL(TBZ_ONLY_TESTBRANCH_32) = TBZ<R32>;
|
||||
DEF_ISEL(TBNZ_ONLY_TESTBRANCH_64) = TBNZ<R64>;
|
||||
DEF_ISEL(TBNZ_ONLY_TESTBRANCH_32) = TBNZ<R32>;
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
|
||||
namespace {
|
||||
|
||||
template <bool (*check_cond)(const State &), typename D,
|
||||
typename S1, typename S2>
|
||||
template <bool (*check_cond)(const State &), typename D, typename S1,
|
||||
typename S2>
|
||||
DEF_SEM(CSEL, D dst, S1 src1, S2 src2) {
|
||||
auto val = check_cond(state) ? Read(src1) : Read(src2);
|
||||
WriteZExt(dst, val);
|
||||
@@ -48,11 +48,10 @@ DEF_COND_ISEL(CSEL_64_CONDSEL, CSEL, R64W, R64, R64)
|
||||
|
||||
namespace {
|
||||
|
||||
template <bool (*check_cond)(const State &), typename D,
|
||||
typename S1, typename S2>
|
||||
template <bool (*check_cond)(const State &), typename D, typename S1,
|
||||
typename S2>
|
||||
DEF_SEM(CSNEG, D dst, S1 src1, S2 src2) {
|
||||
WriteZExt(dst, Select(check_cond(state),
|
||||
Read(src1),
|
||||
WriteZExt(dst, Select(check_cond(state), Read(src1),
|
||||
UAdd(UNot(Read(src2)), ZExtTo<S2>(1))));
|
||||
return memory;
|
||||
}
|
||||
@@ -65,8 +64,8 @@ DEF_COND_ISEL(CSNEG_64_CONDSEL, CSNEG, R64W, R64, R64)
|
||||
|
||||
namespace {
|
||||
|
||||
template <bool (*check_cond)(const State &), typename D,
|
||||
typename S1, typename S2>
|
||||
template <bool (*check_cond)(const State &), typename D, typename S1,
|
||||
typename S2>
|
||||
DEF_SEM(CSINC, D dst, S1 src1, S2 src2) {
|
||||
WriteZExt(dst, Select(check_cond(state), Read(src1), UAdd(Read(src2), 1)));
|
||||
return memory;
|
||||
@@ -78,8 +77,8 @@ DEF_COND_ISEL(CSINC_64_CONDSEL, CSINC, R64W, R64, R64)
|
||||
|
||||
namespace {
|
||||
|
||||
template <bool (*check_cond)(const State &), typename D,
|
||||
typename S1, typename S2>
|
||||
template <bool (*check_cond)(const State &), typename D, typename S1,
|
||||
typename S2>
|
||||
DEF_SEM(CSINV, D dst, S1 src1, S2 src2) {
|
||||
WriteZExt(dst, Select(check_cond(state), Read(src1), UNot(Read(src2))));
|
||||
return memory;
|
||||
|
||||
@@ -18,7 +18,8 @@ namespace {
|
||||
|
||||
template <typename S, typename D>
|
||||
ALWAYS_INLINE static D CheckedCast(State &state, S src) {
|
||||
return CheckedFloatUnaryOp(state, [] (S v) {return static_cast<D>(v);}, src);
|
||||
return CheckedFloatUnaryOp(
|
||||
state, [](S v) { return static_cast<D>(v); }, src);
|
||||
}
|
||||
|
||||
DEF_SEM(UCVTF_UInt32ToFloat32, V128W dst, R32 src) {
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
|
||||
namespace {
|
||||
|
||||
DEF_SEM(StorePairUpdateIndex32, R32 src1, R32 src2, MV64W dst_mem,
|
||||
R64W dst_reg, ADDR next_addr) {
|
||||
DEF_SEM(StorePairUpdateIndex32, R32 src1, R32 src2, MV64W dst_mem, R64W dst_reg,
|
||||
ADDR next_addr) {
|
||||
uint32v2_t vec = {};
|
||||
vec = UInsertV32(vec, 0, Read(src1));
|
||||
vec = UInsertV32(vec, 1, Read(src2));
|
||||
@@ -94,6 +94,7 @@ DEF_ISEL(STP_64_LDSTPAIR_OFF) = StorePair64;
|
||||
|
||||
DEF_ISEL(STP_S_LDSTPAIR_OFF) = STP_S;
|
||||
DEF_ISEL(STP_D_LDSTPAIR_OFF) = STP_D;
|
||||
|
||||
// DEF_ISEL(STP_Q_LDSTPAIR_OFF) = STP_Q;
|
||||
|
||||
namespace {
|
||||
@@ -153,8 +154,8 @@ DEF_ISEL(STR_64_LDST_REGOFF) = StoreToOffset<R64, M64W>;
|
||||
|
||||
namespace {
|
||||
|
||||
DEF_SEM(LoadPairUpdateIndex32, R32W dst1, R32W dst2, MV64 src_mem,
|
||||
R64W dst_reg, ADDR next_addr) {
|
||||
DEF_SEM(LoadPairUpdateIndex32, R32W dst1, R32W dst2, MV64 src_mem, R64W dst_reg,
|
||||
ADDR next_addr) {
|
||||
auto vec = UReadV32(src_mem);
|
||||
WriteZExt(dst1, UExtractV32(vec, 0));
|
||||
WriteZExt(dst2, UExtractV32(vec, 1));
|
||||
@@ -620,8 +621,8 @@ DEF_SEM(LDP_Q, V128W dst1, V128W dst2, MV256 src) {
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(LDP_S_UpdateIndex, V128W dst1, V128W dst2, MV64 src,
|
||||
R64W dst_reg, ADDR next_addr) {
|
||||
DEF_SEM(LDP_S_UpdateIndex, V128W dst1, V128W dst2, MV64 src, R64W dst_reg,
|
||||
ADDR next_addr) {
|
||||
auto src_vec = FReadV32(src);
|
||||
FWriteV32(dst1, FExtractV32(src_vec, 0));
|
||||
FWriteV32(dst2, FExtractV32(src_vec, 1));
|
||||
@@ -629,8 +630,8 @@ DEF_SEM(LDP_S_UpdateIndex, V128W dst1, V128W dst2, MV64 src,
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(LDP_D_UpdateIndex, V128W dst1, V128W dst2, MV128 src,
|
||||
R64W dst_reg, ADDR next_addr) {
|
||||
DEF_SEM(LDP_D_UpdateIndex, V128W dst1, V128W dst2, MV128 src, R64W dst_reg,
|
||||
ADDR next_addr) {
|
||||
auto src_vec = FReadV64(src);
|
||||
FWriteV64(dst1, FExtractV64(src_vec, 0));
|
||||
FWriteV64(dst2, FExtractV64(src_vec, 1));
|
||||
@@ -638,8 +639,8 @@ DEF_SEM(LDP_D_UpdateIndex, V128W dst1, V128W dst2, MV128 src,
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(LDP_Q_UpdateIndex, V128W dst1, V128W dst2, MV256 src,
|
||||
R64W dst_reg, ADDR next_addr) {
|
||||
DEF_SEM(LDP_Q_UpdateIndex, V128W dst1, V128W dst2, MV256 src, R64W dst_reg,
|
||||
ADDR next_addr) {
|
||||
auto src_vec = UReadV128(src);
|
||||
UWriteV128(dst1, UExtractV128(src_vec, 0));
|
||||
UWriteV128(dst2, UExtractV128(src_vec, 1));
|
||||
@@ -860,8 +861,8 @@ namespace {
|
||||
|
||||
#define MAKE_ST1_POSTINDEX(esize) \
|
||||
template <typename D> \
|
||||
DEF_SEM(ST1_PAIR_POSTINDEX_ ## esize, V ## esize src1, V ## esize src2, \
|
||||
D dst, R64W addr_reg, ADDR next_addr) { \
|
||||
DEF_SEM(ST1_PAIR_POSTINDEX_##esize, V##esize src1, V##esize src2, D dst, \
|
||||
R64W addr_reg, ADDR next_addr) { \
|
||||
memory = ST1_PAIR_##esize(memory, state, src1, src2, dst); \
|
||||
Write(addr_reg, Read(next_addr)); \
|
||||
return memory; \
|
||||
@@ -890,8 +891,7 @@ namespace {
|
||||
|
||||
#define MAKE_LD1(esize) \
|
||||
template <typename S> \
|
||||
DEF_SEM(LD1_TRIPLE_ ## esize, V128W dst1, V128W dst2, \
|
||||
V128W dst3, S src) { \
|
||||
DEF_SEM(LD1_TRIPLE_##esize, V128W dst1, V128W dst2, V128W dst3, S src) { \
|
||||
auto elems1 = UReadV##esize(src); \
|
||||
auto elems2 = UReadV##esize(GetElementPtr(src, 1U)); \
|
||||
auto elems3 = UReadV##esize(GetElementPtr(src, 2U)); \
|
||||
@@ -926,8 +926,8 @@ namespace {
|
||||
|
||||
#define MAKE_LD1(esize) \
|
||||
template <typename S> \
|
||||
DEF_SEM(LD1_QUAD_ ## esize, V128W dst1, V128W dst2, \
|
||||
V128W dst3, V128W dst4, S src) { \
|
||||
DEF_SEM(LD1_QUAD_##esize, V128W dst1, V128W dst2, V128W dst3, V128W dst4, \
|
||||
S src) { \
|
||||
auto elems1 = UReadV##esize(src); \
|
||||
auto elems2 = UReadV##esize(GetElementPtr(src, 1U)); \
|
||||
auto elems3 = UReadV##esize(GetElementPtr(src, 2U)); \
|
||||
@@ -964,8 +964,8 @@ namespace {
|
||||
|
||||
#define MAKE_LD1_POSTINDEX(esize) \
|
||||
template <typename S> \
|
||||
DEF_SEM(LD1_SINGLE_POSTINDEX_ ## esize, V128W dst1, S src, \
|
||||
R64W addr_reg, ADDR next_addr) { \
|
||||
DEF_SEM(LD1_SINGLE_POSTINDEX_##esize, V128W dst1, S src, R64W addr_reg, \
|
||||
ADDR next_addr) { \
|
||||
memory = LD1_SINGLE_##esize(memory, state, dst1, src); \
|
||||
Write(addr_reg, Read(next_addr)); \
|
||||
return memory; \
|
||||
@@ -1028,8 +1028,8 @@ namespace {
|
||||
|
||||
#define MAKE_LD1_POSTINDEX(esize) \
|
||||
template <typename S> \
|
||||
DEF_SEM(LD1_TRIPLE_POSTINDEX_ ## esize, V128W dst1, V128W dst2, \
|
||||
V128W dst3, S src, R64W addr_reg, ADDR next_addr) { \
|
||||
DEF_SEM(LD1_TRIPLE_POSTINDEX_##esize, V128W dst1, V128W dst2, V128W dst3, \
|
||||
S src, R64W addr_reg, ADDR next_addr) { \
|
||||
memory = LD1_TRIPLE_##esize(memory, state, dst1, dst2, dst3, src); \
|
||||
Write(addr_reg, Read(next_addr)); \
|
||||
return memory; \
|
||||
@@ -1060,8 +1060,8 @@ namespace {
|
||||
|
||||
#define MAKE_LD1_POSTINDEX(esize) \
|
||||
template <typename S> \
|
||||
DEF_SEM(LD1_QUAD_POSTINDEX_ ## esize, V128W dst1, V128W dst2, \
|
||||
V128W dst3, V128W dst4, S src, R64W addr_reg, ADDR next_addr) { \
|
||||
DEF_SEM(LD1_QUAD_POSTINDEX_##esize, V128W dst1, V128W dst2, V128W dst3, \
|
||||
V128W dst4, S src, R64W addr_reg, ADDR next_addr) { \
|
||||
memory = LD1_QUAD_##esize(memory, state, dst1, dst2, dst3, dst4, src); \
|
||||
Write(addr_reg, Read(next_addr)); \
|
||||
return memory; \
|
||||
@@ -1096,8 +1096,8 @@ namespace {
|
||||
auto vec = UReadV##size(src); \
|
||||
auto dst1_vec = UClearV##size(UReadV##size(dst1)); \
|
||||
auto dst2_vec = UClearV##size(UReadV##size(dst2)); \
|
||||
_Pragma("unroll") \
|
||||
for (size_t i = 0, j = 0; i < NumVectorElems(vec); j++) { \
|
||||
_Pragma("unroll") for (size_t i = 0, j = 0; i < NumVectorElems(vec); \
|
||||
j++) { \
|
||||
dst1_vec = UInsertV##size(dst1_vec, j, UExtractV##size(vec, i++)); \
|
||||
dst2_vec = UInsertV##size(dst2_vec, j, UExtractV##size(vec, i++)); \
|
||||
} \
|
||||
@@ -1163,8 +1163,7 @@ namespace {
|
||||
auto dst1_vec = UClearV##size(UReadV##size(dst1)); \
|
||||
auto dst2_vec = UClearV##size(UReadV##size(dst2)); \
|
||||
auto dst3_vec = UClearV##size(UReadV##size(dst3)); \
|
||||
_Pragma("unroll") \
|
||||
for (size_t i = 0; i < count; ++i) { \
|
||||
_Pragma("unroll") for (size_t i = 0; i < count; ++i) { \
|
||||
auto val = Read(src); \
|
||||
src = GetElementPtr(src, 1); \
|
||||
dst1_vec = UInsertV##size(dst1_vec, i, val); \
|
||||
@@ -1202,14 +1201,12 @@ namespace {
|
||||
|
||||
#define MAKE_LD4(size) \
|
||||
template <typename S, size_t count> \
|
||||
DEF_SEM(LD4_ ## size, V128W dst1, V128W dst2, V128W dst3, \
|
||||
V128W dst4, S src) { \
|
||||
DEF_SEM(LD4_##size, V128W dst1, V128W dst2, V128W dst3, V128W dst4, S src) { \
|
||||
auto dst1_vec = UClearV##size(UReadV##size(dst1)); \
|
||||
auto dst2_vec = UClearV##size(UReadV##size(dst2)); \
|
||||
auto dst3_vec = UClearV##size(UReadV##size(dst3)); \
|
||||
auto dst4_vec = UClearV##size(UReadV##size(dst4)); \
|
||||
_Pragma("unroll") \
|
||||
for (size_t i = 0; i < count; ++i) { \
|
||||
_Pragma("unroll") for (size_t i = 0; i < count; ++i) { \
|
||||
auto val = Read(src); \
|
||||
src = GetElementPtr(src, 1); \
|
||||
dst1_vec = UInsertV##size(dst1_vec, i, val); \
|
||||
@@ -1279,11 +1276,10 @@ namespace {
|
||||
#define EXTRACT_VEC(prefix, size, ext_op) \
|
||||
template <typename D, typename T> \
|
||||
DEF_SEM(prefix##MovFromVec##size, D dst, V128 src, I64 index) { \
|
||||
WriteZExt(dst, ext_op<T>( \
|
||||
prefix ## ExtractV ## size( \
|
||||
prefix ## ReadV ## size(src), Read(index)))); \
|
||||
WriteZExt(dst, ext_op<T>(prefix##ExtractV##size(prefix##ReadV##size(src), \
|
||||
Read(index)))); \
|
||||
return memory; \
|
||||
} \
|
||||
}
|
||||
|
||||
EXTRACT_VEC(U, 8, ZExtTo)
|
||||
EXTRACT_VEC(U, 16, ZExtTo)
|
||||
@@ -1325,8 +1321,7 @@ template <typename V>
|
||||
DEF_SEM(MOVI_N_B, V128W dst, I8 src) {
|
||||
auto imm = Read(src);
|
||||
V res = {};
|
||||
_Pragma("unroll")
|
||||
for (auto &elem : res.elems) {
|
||||
_Pragma("unroll") for (auto &elem : res.elems) {
|
||||
elem = imm;
|
||||
}
|
||||
UWriteV8(dst, res);
|
||||
@@ -1337,8 +1332,7 @@ template <typename V>
|
||||
DEF_SEM(MOVI_L_HL, V128W dst, I16 src) {
|
||||
auto imm = Read(src);
|
||||
V res = {};
|
||||
_Pragma("unroll")
|
||||
for (auto &elem : res.elems) {
|
||||
_Pragma("unroll") for (auto &elem : res.elems) {
|
||||
elem = imm;
|
||||
}
|
||||
UWriteV16(dst, res);
|
||||
@@ -1349,8 +1343,7 @@ template <typename V>
|
||||
DEF_SEM(MOVI_L_SL, V128W dst, I32 src) {
|
||||
auto imm = Read(src);
|
||||
V res = {};
|
||||
_Pragma("unroll")
|
||||
for (auto &elem : res.elems) {
|
||||
_Pragma("unroll") for (auto &elem : res.elems) {
|
||||
elem = imm;
|
||||
}
|
||||
UWriteV32(dst, res);
|
||||
@@ -1365,7 +1358,7 @@ DEF_SEM(MOVI_DS, V128W dst, I64 src) {
|
||||
return memory;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
DEF_ISEL(MOVI_ASIMDIMM_D2_D) = MOVI_D2;
|
||||
DEF_ISEL(MOVI_ASIMDIMM_N_B_8B) = MOVI_N_B<uint8v8_t>;
|
||||
@@ -1384,4 +1377,3 @@ DEF_ISEL(MVNI_ASIMDIMM_L_SL_2S) = MOVI_L_SL<uint32v2_t>;
|
||||
DEF_ISEL(MVNI_ASIMDIMM_L_SL_4S) = MOVI_L_SL<uint32v4_t>;
|
||||
DEF_ISEL(MVNI_ASIMDIMM_M_SM_2S) = MOVI_L_SL<uint32v2_t>;
|
||||
DEF_ISEL(MVNI_ASIMDIMM_M_SM_4S) = MOVI_L_SL<uint32v4_t>;
|
||||
|
||||
|
||||
@@ -18,36 +18,30 @@ namespace {
|
||||
|
||||
// Used to select specializations of flags computations based on what operator
|
||||
// is executed.
|
||||
enum : uint32_t {
|
||||
kLHS = 2415899639U,
|
||||
kRHS = 70623199U
|
||||
};
|
||||
enum : uint32_t { kLHS = 2415899639U, kRHS = 70623199U };
|
||||
|
||||
// Zero flags, tells us whether or not a value is zero.
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool ZeroFlag(T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool ZeroFlag(T res) {
|
||||
return T(0) == res;
|
||||
}
|
||||
|
||||
// Zero flags, tells us whether or not a value is zero.
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool NotZeroFlag(T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool NotZeroFlag(T res) {
|
||||
return T(0) != res;
|
||||
}
|
||||
|
||||
// Sign flag, tells us if a result is signed or unsigned.
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool SignFlag(T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool SignFlag(T res) {
|
||||
return 0 > Signed(res);
|
||||
}
|
||||
|
||||
// Tests whether there is an even number of bits in the low order byte.
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool ParityFlag(uint8_t r0) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool ParityFlag(uint8_t r0) {
|
||||
return !__builtin_parity(static_cast<unsigned>(r0));
|
||||
|
||||
// auto r1 = r0 >> 1_u8;
|
||||
// auto r2 = r1 >> 1_u8;
|
||||
// auto r3 = r2 >> 1_u8;
|
||||
@@ -72,13 +66,10 @@ struct Overflow;
|
||||
template <>
|
||||
struct Overflow<tag_add> {
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Invalid specialization of `Overflow::Flag` for addition.");
|
||||
enum {
|
||||
kSignShift = sizeof(T) * 8 - 1
|
||||
};
|
||||
enum { kSignShift = sizeof(T) * 8 - 1 };
|
||||
|
||||
const T sign_lhs = lhs >> kSignShift;
|
||||
const T sign_rhs = rhs >> kSignShift;
|
||||
@@ -91,14 +82,11 @@ struct Overflow<tag_add> {
|
||||
template <>
|
||||
struct Overflow<tag_sub> {
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Invalid specialization of `Overflow::Flag` for "
|
||||
"subtraction.");
|
||||
enum {
|
||||
kSignShift = sizeof(T) * 8 - 1
|
||||
};
|
||||
enum { kSignShift = sizeof(T) * 8 - 1 };
|
||||
|
||||
const T sign_lhs = lhs >> kSignShift;
|
||||
const T sign_rhs = rhs >> kSignShift;
|
||||
@@ -114,9 +102,8 @@ struct Overflow<tag_mul> {
|
||||
// Integer multiplication overflow check, where result is twice the width of
|
||||
// the operands.
|
||||
template <typename T, typename R>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool Flag(
|
||||
T, T, R res,
|
||||
[[gnu::const]] ALWAYS_INLINE static bool
|
||||
Flag(T, T, R res,
|
||||
typename std::enable_if<sizeof(T) < sizeof(R), int>::type = 0) {
|
||||
|
||||
return static_cast<R>(static_cast<T>(res)) != res;
|
||||
@@ -125,9 +112,8 @@ struct Overflow<tag_mul> {
|
||||
// Signed integer multiplication overflow check, where the result is
|
||||
// truncated to the size of the operands.
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool Flag(
|
||||
T lhs, T rhs, T,
|
||||
[[gnu::const]] ALWAYS_INLINE static bool
|
||||
Flag(T lhs, T rhs, T,
|
||||
typename std::enable_if<std::is_signed<T>::value, int>::type = 0) {
|
||||
auto lhs_wide = SExt(lhs);
|
||||
auto rhs_wide = SExt(rhs);
|
||||
@@ -143,8 +129,7 @@ struct Carry;
|
||||
template <>
|
||||
struct Carry<tag_add> {
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Invalid specialization of `Carry::Flag` for addition.");
|
||||
return res < lhs || res < rhs;
|
||||
@@ -155,8 +140,7 @@ struct Carry<tag_add> {
|
||||
template <>
|
||||
struct Carry<tag_sub> {
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool Flag(T lhs, T rhs, T) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Invalid specialization of `Carry::Flag` for addition.");
|
||||
return lhs < rhs;
|
||||
@@ -171,9 +155,9 @@ ALWAYS_INLINE static void SetFPSRStatusFlags(State &state, int mask) {
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
ALWAYS_INLINE static
|
||||
auto CheckedFloatUnaryOp(State &state, F func, T arg1)
|
||||
ALWAYS_INLINE static auto CheckedFloatUnaryOp(State &state, F func, T arg1)
|
||||
-> decltype(func(arg1)) {
|
||||
|
||||
//state.sr.idc |= IsDenormal(arg1);
|
||||
auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT);
|
||||
BarrierReorder();
|
||||
@@ -186,9 +170,10 @@ auto CheckedFloatUnaryOp(State &state, F func, T arg1)
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
ALWAYS_INLINE static
|
||||
auto CheckedFloatBinOp(State &state, F func, T arg1, T arg2)
|
||||
ALWAYS_INLINE static auto CheckedFloatBinOp(State &state, F func, T arg1,
|
||||
T arg2)
|
||||
-> decltype(func(arg1, arg2)) {
|
||||
|
||||
//state.sr.idc |= IsDenormal(arg1) | IsDenormal(arg2);
|
||||
auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT);
|
||||
BarrierReorder();
|
||||
|
||||
@@ -136,8 +136,8 @@ template <typename D, typename S>
|
||||
DEF_SEM(ASRV, D dst, S src1, S src2) {
|
||||
using T = typename BaseType<S>::BT;
|
||||
constexpr auto size = T(sizeof(T) * 8);
|
||||
WriteZExt(
|
||||
dst, Unsigned(SShr(Signed(Read(src1)), Signed(URem(Read(src2), size)))));
|
||||
WriteZExt(dst,
|
||||
Unsigned(SShr(Signed(Read(src1)), Signed(URem(Read(src2), size)))));
|
||||
return memory;
|
||||
}
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ DEF_SEM(EOR_Vec, V128W dst, S src1, S src2) {
|
||||
auto operand1 = UReadV64(src2);
|
||||
auto operand2 = UClearV64(operand4);
|
||||
auto operand3 = UNotV64(operand2);
|
||||
UWriteV64(dst, UXorV64(
|
||||
operand1, UAndV64(UXorV64(operand2, operand4), operand3)));
|
||||
UWriteV64(dst,
|
||||
UXorV64(operand1, UAndV64(UXorV64(operand2, operand4), operand3)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ DEF_SEM(BIT_Vec, V128W dst, S dst_src, S src1, S src2) {
|
||||
auto operand4 = UReadV64(src1);
|
||||
auto operand1 = UReadV64(dst_src);
|
||||
auto operand3 = UReadV64(src2);
|
||||
UWriteV64(dst, UXorV64(
|
||||
operand1, UAndV64(UXorV64(operand1, operand4), operand3)));
|
||||
UWriteV64(dst,
|
||||
UXorV64(operand1, UAndV64(UXorV64(operand1, operand4), operand3)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -60,8 +60,8 @@ DEF_SEM(BIF_Vec, V128W dst, S dst_src, S src1, S src2) {
|
||||
auto operand4 = UReadV64(src1);
|
||||
auto operand1 = UReadV64(dst_src);
|
||||
auto operand3 = UNotV64(UReadV64(src2));
|
||||
UWriteV64(dst, UXorV64(
|
||||
operand1, UAndV64(UXorV64(operand1, operand4), operand3)));
|
||||
UWriteV64(dst,
|
||||
UXorV64(operand1, UAndV64(UXorV64(operand1, operand4), operand3)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -70,8 +70,8 @@ DEF_SEM(BSL_Vec, V128W dst, S dst_src, S src1, S src2) {
|
||||
auto operand4 = UReadV64(src1);
|
||||
auto operand1 = UReadV64(src2);
|
||||
auto operand3 = UReadV64(dst_src);
|
||||
UWriteV64(dst, UXorV64(
|
||||
operand1, UAndV64(UXorV64(operand1, operand4), operand3)));
|
||||
UWriteV64(dst,
|
||||
UXorV64(operand1, UAndV64(UXorV64(operand1, operand4), operand3)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -126,8 +126,7 @@ namespace {
|
||||
DEF_SEM(DUP_##size, V128W dst, R64 src) { \
|
||||
auto val = TruncTo<uint##size##_t>(Read(src)); \
|
||||
V vec = {}; \
|
||||
_Pragma("unroll") \
|
||||
for (auto &element : vec.elems) { \
|
||||
_Pragma("unroll") for (auto &element : vec.elems) { \
|
||||
element = val; \
|
||||
} \
|
||||
UWriteV##size(dst, vec); \
|
||||
@@ -172,8 +171,8 @@ ALWAYS_INLINE static T UMax(T lhs, T rhs) {
|
||||
auto vec1 = prefix##ReadV##size(src1); \
|
||||
auto vec2 = prefix##ReadV##size(src2); \
|
||||
V sum = {}; \
|
||||
_Pragma("unroll") \
|
||||
for (size_t i = 0, max_i = NumVectorElems(sum); i < max_i; ++i) { \
|
||||
_Pragma("unroll") for (size_t i = 0, max_i = NumVectorElems(sum); \
|
||||
i < max_i; ++i) { \
|
||||
sum.elems[i] = prefix##binop(prefix##ExtractV##size(vec1, i), \
|
||||
prefix##ExtractV##size(vec2, i)); \
|
||||
} \
|
||||
@@ -266,12 +265,11 @@ namespace {
|
||||
decltype(ucmp_val) zeros = 0; \
|
||||
decltype(ucmp_val) ones = ~zeros; \
|
||||
V res = {}; \
|
||||
_Pragma("unroll") \
|
||||
for (size_t i = 0, max_i = NumVectorElems(res); i < max_i; ++i) { \
|
||||
res.elems[i] = Select( \
|
||||
prefix ## binop(prefix ## ExtractV ## size(vec1, i), cmp_val), \
|
||||
ones, \
|
||||
zeros); \
|
||||
_Pragma("unroll") for (size_t i = 0, max_i = NumVectorElems(res); \
|
||||
i < max_i; ++i) { \
|
||||
res.elems[i] = \
|
||||
Select(prefix##binop(prefix##ExtractV##size(vec1, i), cmp_val), \
|
||||
ones, zeros); \
|
||||
} \
|
||||
UWriteV##size(dst, res); \
|
||||
return memory; \
|
||||
@@ -364,13 +362,11 @@ namespace {
|
||||
uint##size##_t zeros = 0; \
|
||||
uint##size##_t ones = ~zeros; \
|
||||
V res = {}; \
|
||||
_Pragma("unroll") \
|
||||
for (size_t i = 0, max_i = NumVectorElems(res); i < max_i; ++i) { \
|
||||
res.elems[i] = Select( \
|
||||
prefix ## binop(prefix ## ExtractV ## size(vec1, i), \
|
||||
_Pragma("unroll") for (size_t i = 0, max_i = NumVectorElems(res); \
|
||||
i < max_i; ++i) { \
|
||||
res.elems[i] = Select(prefix##binop(prefix##ExtractV##size(vec1, i), \
|
||||
prefix##ExtractV##size(vec2, i)), \
|
||||
ones, \
|
||||
zeros); \
|
||||
ones, zeros); \
|
||||
} \
|
||||
UWriteV##size(dst, res); \
|
||||
return memory; \
|
||||
@@ -450,16 +446,12 @@ namespace {
|
||||
V res = {}; \
|
||||
size_t max_i = NumVectorElems(res); \
|
||||
size_t j = 0; \
|
||||
_Pragma("unroll") \
|
||||
for (size_t i = 0; i < max_i; i += 2) { \
|
||||
res.elems[j++] = prefix ## binop( \
|
||||
prefix ## ExtractV ## size(vec1, i), \
|
||||
_Pragma("unroll") for (size_t i = 0; i < max_i; i += 2) { \
|
||||
res.elems[j++] = prefix##binop(prefix##ExtractV##size(vec1, i), \
|
||||
prefix##ExtractV##size(vec1, i + 1)); \
|
||||
} \
|
||||
_Pragma("unroll") \
|
||||
for (size_t i = 0; i < max_i; i += 2) { \
|
||||
res.elems[j++] = prefix ## binop( \
|
||||
prefix ## ExtractV ## size(vec2, i), \
|
||||
_Pragma("unroll") for (size_t i = 0; i < max_i; i += 2) { \
|
||||
res.elems[j++] = prefix##binop(prefix##ExtractV##size(vec2, i), \
|
||||
prefix##ExtractV##size(vec2, i + 1)); \
|
||||
} \
|
||||
prefix##WriteV##size(dst, res); \
|
||||
@@ -596,8 +588,7 @@ template <typename S>
|
||||
DEF_SEM(UMINV_8, V128W dst, S src) {
|
||||
auto vec = UReadV8(src);
|
||||
auto val = std::numeric_limits<uint8_t>::max();
|
||||
_Pragma("unroll")
|
||||
for (auto elem : vec.elems) {
|
||||
_Pragma("unroll") for (auto elem : vec.elems) {
|
||||
val = UMin(elem, val);
|
||||
}
|
||||
UWriteV8(dst, val);
|
||||
@@ -608,8 +599,7 @@ template <typename S>
|
||||
DEF_SEM(UMINV_16, V128W dst, S src) {
|
||||
auto vec = UReadV16(src);
|
||||
auto val = std::numeric_limits<uint16_t>::max();
|
||||
_Pragma("unroll")
|
||||
for (auto elem : vec.elems) {
|
||||
_Pragma("unroll") for (auto elem : vec.elems) {
|
||||
val = UMin(elem, val);
|
||||
}
|
||||
UWriteV16(dst, val);
|
||||
@@ -620,8 +610,7 @@ template <typename S>
|
||||
DEF_SEM(UMINV_32, V128W dst, S src) {
|
||||
auto vec = UReadV32(src);
|
||||
auto val = std::numeric_limits<uint32_t>::max();
|
||||
_Pragma("unroll")
|
||||
for (auto elem : vec.elems) {
|
||||
_Pragma("unroll") for (auto elem : vec.elems) {
|
||||
val = UMin(elem, val);
|
||||
}
|
||||
UWriteV32(dst, val);
|
||||
@@ -632,8 +621,7 @@ template <typename S>
|
||||
DEF_SEM(SMINV_8, V128W dst, S src) {
|
||||
auto vec = SReadV8(src);
|
||||
auto val = std::numeric_limits<int8_t>::max();
|
||||
_Pragma("unroll")
|
||||
for (auto elem : vec.elems) {
|
||||
_Pragma("unroll") for (auto elem : vec.elems) {
|
||||
val = SMin(elem, val);
|
||||
}
|
||||
SWriteV8(dst, val);
|
||||
@@ -644,8 +632,7 @@ template <typename S>
|
||||
DEF_SEM(SMINV_16, V128W dst, S src) {
|
||||
auto vec = SReadV16(src);
|
||||
auto val = std::numeric_limits<int16_t>::max();
|
||||
_Pragma("unroll")
|
||||
for (auto elem : vec.elems) {
|
||||
_Pragma("unroll") for (auto elem : vec.elems) {
|
||||
val = SMin(elem, val);
|
||||
}
|
||||
SWriteV16(dst, val);
|
||||
@@ -656,8 +643,7 @@ template <typename S>
|
||||
DEF_SEM(SMINV_32, V128W dst, S src) {
|
||||
auto vec = SReadV32(src);
|
||||
auto val = std::numeric_limits<int32_t>::max();
|
||||
_Pragma("unroll")
|
||||
for (auto elem : vec.elems) {
|
||||
_Pragma("unroll") for (auto elem : vec.elems) {
|
||||
val = SMin(elem, val);
|
||||
}
|
||||
SWriteV32(dst, val);
|
||||
@@ -668,8 +654,7 @@ template <typename S>
|
||||
DEF_SEM(UMAXV_8, V128W dst, S src) {
|
||||
auto vec = UReadV8(src);
|
||||
auto val = std::numeric_limits<uint8_t>::min();
|
||||
_Pragma("unroll")
|
||||
for (auto elem : vec.elems) {
|
||||
_Pragma("unroll") for (auto elem : vec.elems) {
|
||||
val = UMax(elem, val);
|
||||
}
|
||||
UWriteV8(dst, val);
|
||||
@@ -680,8 +665,7 @@ template <typename S>
|
||||
DEF_SEM(UMAXV_16, V128W dst, S src) {
|
||||
auto vec = UReadV16(src);
|
||||
auto val = std::numeric_limits<uint16_t>::min();
|
||||
_Pragma("unroll")
|
||||
for (auto elem : vec.elems) {
|
||||
_Pragma("unroll") for (auto elem : vec.elems) {
|
||||
val = UMax(elem, val);
|
||||
}
|
||||
UWriteV16(dst, val);
|
||||
@@ -692,8 +676,7 @@ template <typename S>
|
||||
DEF_SEM(UMAXV_32, V128W dst, S src) {
|
||||
auto vec = UReadV32(src);
|
||||
auto val = std::numeric_limits<uint32_t>::min();
|
||||
_Pragma("unroll")
|
||||
for (auto elem : vec.elems) {
|
||||
_Pragma("unroll") for (auto elem : vec.elems) {
|
||||
val = UMax(elem, val);
|
||||
}
|
||||
UWriteV32(dst, val);
|
||||
@@ -704,8 +687,7 @@ template <typename S>
|
||||
DEF_SEM(SMAXV_8, V128W dst, S src) {
|
||||
auto vec = SReadV8(src);
|
||||
auto val = std::numeric_limits<int8_t>::min();
|
||||
_Pragma("unroll")
|
||||
for (auto elem : vec.elems) {
|
||||
_Pragma("unroll") for (auto elem : vec.elems) {
|
||||
val = SMax(elem, val);
|
||||
}
|
||||
SWriteV8(dst, val);
|
||||
@@ -716,8 +698,7 @@ template <typename S>
|
||||
DEF_SEM(SMAXV_16, V128W dst, S src) {
|
||||
auto vec = SReadV16(src);
|
||||
auto val = std::numeric_limits<int16_t>::min();
|
||||
_Pragma("unroll")
|
||||
for (auto elem : vec.elems) {
|
||||
_Pragma("unroll") for (auto elem : vec.elems) {
|
||||
val = SMax(elem, val);
|
||||
}
|
||||
SWriteV16(dst, val);
|
||||
@@ -728,8 +709,7 @@ template <typename S>
|
||||
DEF_SEM(SMAXV_32, V128W dst, S src) {
|
||||
auto vec = SReadV32(src);
|
||||
auto val = std::numeric_limits<int32_t>::min();
|
||||
_Pragma("unroll")
|
||||
for (auto elem : vec.elems) {
|
||||
_Pragma("unroll") for (auto elem : vec.elems) {
|
||||
val = SMax(elem, val);
|
||||
}
|
||||
SWriteV32(dst, val);
|
||||
@@ -863,12 +843,10 @@ DEF_SEM(EXT, V128W dst, T src1, T src2, I32 src3) {
|
||||
auto vn = UReadV8(src1);
|
||||
auto vm = UReadV8(src2);
|
||||
uint8v16_t result = {};
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0, max_i = count; i+lsb < max_i; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0, max_i = count; i + lsb < max_i; ++i) {
|
||||
result.elems[count - 1 - i] = UExtractV8(vm, i + lsb);
|
||||
}
|
||||
_Pragma("unroll")
|
||||
for (size_t i = lsb; i < count; ++i) {
|
||||
_Pragma("unroll") for (size_t i = lsb; i < count; ++i) {
|
||||
result.elems[count - 1 - i] = UExtractV8(vn, i - lsb);
|
||||
}
|
||||
UWriteV8(dst, result);
|
||||
|
||||
@@ -24,8 +24,8 @@ DEF_SEM(CallSupervisor, I32 imm) {
|
||||
|
||||
DEF_SEM(Breakpoint, I32 imm) {
|
||||
HYPER_CALL_VECTOR = Read(imm);
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAArch64Breakpoint);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kAArch64Breakpoint);
|
||||
}
|
||||
|
||||
DEF_SEM(DoMRS_RS_SYSTEM_FPSR, R64W dest) {
|
||||
@@ -33,6 +33,7 @@ DEF_SEM(DoMRS_RS_SYSTEM_FPSR, R64W dest) {
|
||||
fpsr.ixc = state.sr.ixc;
|
||||
fpsr.ofc = state.sr.ofc;
|
||||
fpsr.ufc = state.sr.ufc;
|
||||
|
||||
//fpsr.idc = state.sr.idc; // TODO(garret): fix the saving of the idc bit before reenabling (issue #188)
|
||||
fpsr.ioc = state.sr.ioc;
|
||||
WriteZExt(dest, fpsr.flat);
|
||||
@@ -49,6 +50,7 @@ DEF_SEM(DoMSR_SR_SYSTEM_FPSR, R64 src) {
|
||||
state.sr.ofc = fpsr.ofc;
|
||||
state.sr.ixc = fpsr.ixc;
|
||||
state.sr.ufc = fpsr.ufc;
|
||||
|
||||
//state.sr.idc = fpsr.idc; // TODO(garret): fix the saving of the idc bit before reenabling (issue #188)
|
||||
return memory;
|
||||
}
|
||||
@@ -79,6 +81,7 @@ DEF_SEM(DoMSR_SR_SYSTEM_TPIDR_EL0, R64 src) {
|
||||
}
|
||||
|
||||
DEF_SEM(DataMemoryBarrier) {
|
||||
|
||||
// TODO(pag): Full-system data memory barrier probably requires a synchronous
|
||||
// hypercall if it behaves kind of like Linux's `sys_membarrier`.
|
||||
return __remill_barrier_store_store(memory);
|
||||
|
||||
+103
-137
@@ -14,36 +14,33 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "remill/Arch/Arch.h"
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
#include <llvm/ADT/APInt.h>
|
||||
#include <llvm/ADT/SmallVector.h>
|
||||
#include <llvm/IR/BasicBlock.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/IntrinsicInst.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Metadata.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <llvm/ADT/APInt.h>
|
||||
#include <llvm/ADT/SmallVector.h>
|
||||
|
||||
#include <llvm/IR/BasicBlock.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/IntrinsicInst.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Metadata.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
|
||||
#include "remill/Arch/Arch.h"
|
||||
#include "remill/Arch/Name.h"
|
||||
|
||||
#include "remill/BC/ABI.h"
|
||||
#include "remill/BC/Compat/Attributes.h"
|
||||
#include "remill/BC/Compat/DebugInfo.h"
|
||||
#include "remill/BC/Compat/GlobalValue.h"
|
||||
#include "remill/BC/Util.h"
|
||||
#include "remill/BC/Version.h"
|
||||
|
||||
#include "remill/OS/OS.h"
|
||||
|
||||
DEFINE_string(arch, REMILL_ARCH,
|
||||
@@ -57,7 +54,6 @@ namespace remill {
|
||||
|
||||
class Arch::Impl {
|
||||
public:
|
||||
|
||||
// State type.
|
||||
llvm::StructType *state_type{nullptr};
|
||||
|
||||
@@ -81,13 +77,11 @@ static unsigned AddressSize(ArchName arch_name) {
|
||||
return 0;
|
||||
case kArchX86:
|
||||
case kArchX86_AVX:
|
||||
case kArchX86_AVX512:
|
||||
return 32;
|
||||
case kArchX86_AVX512: return 32;
|
||||
case kArchAMD64:
|
||||
case kArchAMD64_AVX:
|
||||
case kArchAMD64_AVX512:
|
||||
case kArchAArch64LittleEndian:
|
||||
return 64;
|
||||
case kArchAArch64LittleEndian: return 64;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -102,8 +96,7 @@ Arch::Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_)
|
||||
|
||||
Arch::~Arch(void) {}
|
||||
|
||||
bool Arch::LazyDecodeInstruction(
|
||||
uint64_t address, std::string_view instr_bytes,
|
||||
bool Arch::LazyDecodeInstruction(uint64_t address, std::string_view instr_bytes,
|
||||
Instruction &inst) const {
|
||||
return DecodeInstruction(address, instr_bytes, inst);
|
||||
}
|
||||
@@ -119,8 +112,7 @@ bool Arch::MayHaveDelaySlot(const Instruction &) const {
|
||||
}
|
||||
|
||||
// Returns `true` if a given instruction might have a delay slot.
|
||||
bool Arch::NextInstructionIsDelayed(const Instruction &,
|
||||
const Instruction &,
|
||||
bool Arch::NextInstructionIsDelayed(const Instruction &, const Instruction &,
|
||||
bool) const {
|
||||
return false;
|
||||
}
|
||||
@@ -128,9 +120,7 @@ bool Arch::NextInstructionIsDelayed(const Instruction &,
|
||||
llvm::Triple Arch::BasicTriple(void) const {
|
||||
llvm::Triple triple;
|
||||
switch (os_name) {
|
||||
case kOSInvalid:
|
||||
LOG(FATAL) << "Cannot get triple OS.";
|
||||
break;
|
||||
case kOSInvalid: LOG(FATAL) << "Cannot get triple OS."; break;
|
||||
|
||||
case kOSLinux:
|
||||
triple.setOS(llvm::Triple::Linux);
|
||||
@@ -163,8 +153,7 @@ llvm::Triple Arch::BasicTriple(void) const {
|
||||
return triple;
|
||||
}
|
||||
|
||||
auto Arch::Build(llvm::LLVMContext *context_,
|
||||
OSName os_name_,
|
||||
auto Arch::Build(llvm::LLVMContext *context_, OSName os_name_,
|
||||
ArchName arch_name_) -> ArchPtr {
|
||||
|
||||
switch (arch_name_) {
|
||||
@@ -209,7 +198,8 @@ auto Arch::Build(llvm::LLVMContext *context_,
|
||||
}
|
||||
}
|
||||
|
||||
const Arch *Arch::Get(llvm::LLVMContext &context, OSName os, ArchName arch_name) {
|
||||
const Arch *Arch::Get(llvm::LLVMContext &context, OSName os,
|
||||
ArchName arch_name) {
|
||||
return Arch::Build(&context, os, arch_name).release();
|
||||
}
|
||||
|
||||
@@ -282,11 +272,13 @@ namespace {
|
||||
// be removed in favor of Arch::Build/Get* but some old code may
|
||||
// depend on this caching behaviour.
|
||||
struct AvailableArchs {
|
||||
using ArchMap = std::unordered_map<llvm::LLVMContext *, std::unique_ptr<const Arch>>;
|
||||
using ArchMap =
|
||||
std::unordered_map<llvm::LLVMContext *, std::unique_ptr<const Arch>>;
|
||||
|
||||
static ArchMap cached;
|
||||
|
||||
static const Arch *GetOrCreate(llvm::LLVMContext *ctx, OSName os, ArchName name) {
|
||||
static const Arch *GetOrCreate(llvm::LLVMContext *ctx, OSName os,
|
||||
ArchName name) {
|
||||
auto &arch = cached[ctx];
|
||||
if (!arch) {
|
||||
arch = Create(ctx, os, name);
|
||||
@@ -300,14 +292,16 @@ struct AvailableArchs {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static Arch::ArchPtr Create(llvm::LLVMContext *ctx, OSName os, ArchName name) {
|
||||
static Arch::ArchPtr Create(llvm::LLVMContext *ctx, OSName os,
|
||||
ArchName name) {
|
||||
return Arch::Build(ctx, os, name);
|
||||
}
|
||||
};
|
||||
|
||||
AvailableArchs::ArchMap AvailableArchs::cached = {};
|
||||
|
||||
static const Arch *GetOrCreate(llvm::LLVMContext &ctx, OSName os, ArchName name) {
|
||||
static const Arch *GetOrCreate(llvm::LLVMContext &ctx, OSName os,
|
||||
ArchName name) {
|
||||
return AvailableArchs::GetOrCreate(&ctx, os, name);
|
||||
}
|
||||
|
||||
@@ -331,10 +325,8 @@ bool Arch::IsX86(void) const {
|
||||
switch (arch_name) {
|
||||
case remill::kArchX86:
|
||||
case remill::kArchX86_AVX:
|
||||
case remill::kArchX86_AVX512:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
case remill::kArchX86_AVX512: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,10 +334,8 @@ bool Arch::IsAMD64(void) const {
|
||||
switch (arch_name) {
|
||||
case remill::kArchAMD64:
|
||||
case remill::kArchAMD64_AVX:
|
||||
case remill::kArchAMD64_AVX512:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
case remill::kArchAMD64_AVX512: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,8 +380,8 @@ static bool GetRegisterOffset(llvm::Module *module, llvm::Type *state_ptr_type,
|
||||
if (auto gep = llvm::dyn_cast<llvm::GetElementPtrInst>(reg)) {
|
||||
llvm::APInt gep_offset(dl.getPointerSizeInBits(0), 0);
|
||||
if (!gep->accumulateConstantOffset(dl, gep_offset)) {
|
||||
DLOG(INFO)
|
||||
<< "Named variable " << val_name << " is not a register in the "
|
||||
DLOG(INFO) << "Named variable " << val_name
|
||||
<< " is not a register in the "
|
||||
<< "state structure";
|
||||
}
|
||||
*offset += gep_offset.getZExtValue();
|
||||
@@ -405,15 +395,14 @@ static bool GetRegisterOffset(llvm::Module *module, llvm::Type *state_ptr_type,
|
||||
break;
|
||||
|
||||
} else {
|
||||
DLOG(INFO)
|
||||
<< "Named variable " << val_name << " is not a register in the "
|
||||
DLOG(INFO) << "Named variable " << val_name
|
||||
<< " is not a register in the "
|
||||
<< "state structure";
|
||||
return false;
|
||||
}
|
||||
} while (reg);
|
||||
|
||||
DLOG(INFO)
|
||||
<< "Offset of register " << val_name << " in state structure is "
|
||||
DLOG(INFO) << "Offset of register " << val_name << " in state structure is "
|
||||
<< *offset;
|
||||
|
||||
return true;
|
||||
@@ -457,8 +446,8 @@ static void FixupBasicBlockVariables(llvm::Function *basic_block) {
|
||||
|
||||
// Get stores.
|
||||
} else if (auto store_inst = llvm::dyn_cast<llvm::StoreInst>(&inst)) {
|
||||
auto dst_alloca = llvm::dyn_cast<llvm::AllocaInst>(
|
||||
store_inst->getPointerOperand());
|
||||
auto dst_alloca =
|
||||
llvm::dyn_cast<llvm::AllocaInst>(store_inst->getPointerOperand());
|
||||
if (dst_alloca) {
|
||||
stored_val[dst_alloca] = store_inst->getValueOperand();
|
||||
}
|
||||
@@ -466,8 +455,8 @@ static void FixupBasicBlockVariables(llvm::Function *basic_block) {
|
||||
|
||||
// Forward stores to loads.
|
||||
} else if (auto load_inst = llvm::dyn_cast<llvm::LoadInst>(&inst)) {
|
||||
auto src_alloca = llvm::dyn_cast<llvm::AllocaInst>(
|
||||
load_inst->getPointerOperand());
|
||||
auto src_alloca =
|
||||
llvm::dyn_cast<llvm::AllocaInst>(load_inst->getPointerOperand());
|
||||
if (src_alloca) {
|
||||
if (auto val = stored_val[src_alloca]) {
|
||||
load_inst->replaceAllUsesWith(val);
|
||||
@@ -478,8 +467,7 @@ static void FixupBasicBlockVariables(llvm::Function *basic_block) {
|
||||
} else if (llvm::isa<llvm::BranchInst>(&inst) ||
|
||||
llvm::isa<llvm::CallInst>(&inst) ||
|
||||
llvm::isa<llvm::InvokeInst>(&inst)) {
|
||||
LOG(FATAL)
|
||||
<< "Unsupported instruction in __remill_basic_block: "
|
||||
LOG(FATAL) << "Unsupported instruction in __remill_basic_block: "
|
||||
<< LLVMThingToString(&inst);
|
||||
}
|
||||
}
|
||||
@@ -558,8 +546,7 @@ static void FixupBasicBlockVariables(llvm::Function *basic_block) {
|
||||
auto name_it = names.find(&inst);
|
||||
if (name_it != names.end()) {
|
||||
auto &entry = *name_it;
|
||||
if (!entry.first->hasName() &&
|
||||
!entry.first->getType()->isVoidTy() &&
|
||||
if (!entry.first->hasName() && !entry.first->getType()->isVoidTy() &&
|
||||
!used_names.count(entry.second)) {
|
||||
entry.first->setName(entry.second);
|
||||
used_names.insert(entry.second);
|
||||
@@ -574,18 +561,10 @@ static void FixupBasicBlockVariables(llvm::Function *basic_block) {
|
||||
|
||||
// Add attributes to llvm::Argument in a way portable across LLVMs
|
||||
static void AddNoAliasToArgument(llvm::Argument *arg) {
|
||||
IF_LLVM_LT_390(
|
||||
arg->addAttr(
|
||||
llvm::AttributeSet::get(
|
||||
arg->getContext(),
|
||||
arg->getArgNo() + 1,
|
||||
llvm::Attribute::NoAlias)
|
||||
);
|
||||
);
|
||||
IF_LLVM_LT_390(arg->addAttr(llvm::AttributeSet::get(
|
||||
arg->getContext(), arg->getArgNo() + 1, llvm::Attribute::NoAlias)););
|
||||
|
||||
IF_LLVM_GTE_390(
|
||||
arg->addAttr(llvm::Attribute::NoAlias);
|
||||
);
|
||||
IF_LLVM_GTE_390(arg->addAttr(llvm::Attribute::NoAlias););
|
||||
}
|
||||
|
||||
// ensures that mandatory remill functions have the correct
|
||||
@@ -617,6 +596,7 @@ static void PrepareModuleRemillFunctions(llvm::Module *mod) {
|
||||
|
||||
// Compare two registers for sorting.
|
||||
static bool RegisterComparator(const Register &lhs, const Register &rhs) {
|
||||
|
||||
// Bigger to appear later in the array. E.g. RAX before EAX.
|
||||
if (lhs.size > rhs.size) {
|
||||
return true;
|
||||
@@ -692,8 +672,7 @@ static unsigned Complexity(llvm::Value *base, llvm::Type *state_ptr_type) {
|
||||
break;
|
||||
|
||||
} else {
|
||||
LOG(FATAL)
|
||||
<< "Unexpected value " << LLVMThingToString(base)
|
||||
LOG(FATAL) << "Unexpected value " << LLVMThingToString(base)
|
||||
<< " in State structure indexing chain";
|
||||
base = nullptr;
|
||||
}
|
||||
@@ -705,12 +684,11 @@ static unsigned Complexity(llvm::Value *base, llvm::Type *state_ptr_type) {
|
||||
static uint64_t TotalOffset(const llvm::DataLayout &dl, llvm::Value *base,
|
||||
llvm::Type *state_ptr_type) {
|
||||
uint64_t total_offset = 0;
|
||||
const auto state_size = dl.getTypeAllocSize(
|
||||
state_ptr_type->getPointerElementType());
|
||||
const auto state_size =
|
||||
dl.getTypeAllocSize(state_ptr_type->getPointerElementType());
|
||||
while (base) {
|
||||
if (auto gep = llvm::dyn_cast<llvm::GEPOperator>(base); gep) {
|
||||
llvm::APInt accumulated_offset(
|
||||
dl.getPointerSizeInBits(0), 0, false);
|
||||
llvm::APInt accumulated_offset(dl.getPointerSizeInBits(0), 0, false);
|
||||
CHECK(gep->accumulateConstantOffset(dl, accumulated_offset));
|
||||
auto curr_offset = accumulated_offset.getZExtValue();
|
||||
CHECK_LT(curr_offset, state_size);
|
||||
@@ -732,8 +710,7 @@ static uint64_t TotalOffset(const llvm::DataLayout &dl, llvm::Value *base,
|
||||
break;
|
||||
|
||||
} else {
|
||||
LOG(FATAL)
|
||||
<< "Unexpected value " << LLVMThingToString(base)
|
||||
LOG(FATAL) << "Unexpected value " << LLVMThingToString(base)
|
||||
<< " in State structure indexing chain";
|
||||
base = nullptr;
|
||||
}
|
||||
@@ -741,11 +718,10 @@ static uint64_t TotalOffset(const llvm::DataLayout &dl, llvm::Value *base,
|
||||
return total_offset;
|
||||
}
|
||||
|
||||
static llvm::Value *FinishAddressOf(
|
||||
llvm::IRBuilder<> &ir, const llvm::DataLayout &dl,
|
||||
llvm::Type *state_ptr_type,
|
||||
size_t state_size, const Register *reg, unsigned addr_space,
|
||||
llvm::Value *gep) {
|
||||
static llvm::Value *
|
||||
FinishAddressOf(llvm::IRBuilder<> &ir, const llvm::DataLayout &dl,
|
||||
llvm::Type *state_ptr_type, size_t state_size,
|
||||
const Register *reg, unsigned addr_space, llvm::Value *gep) {
|
||||
|
||||
auto gep_offset = TotalOffset(dl, gep, state_ptr_type);
|
||||
auto gep_type_at_offset = gep->getType()->getPointerElementType();
|
||||
@@ -777,13 +753,12 @@ static llvm::Value *FinishAddressOf(
|
||||
// `goal_ptr_type` and index.
|
||||
if (((diff / reg->size) * reg->size) == diff) {
|
||||
llvm::Value *elem_indexes[] = {
|
||||
llvm::ConstantInt::get(index_type, diff / reg->size, false)
|
||||
};
|
||||
llvm::ConstantInt::get(index_type, diff / reg->size, false)};
|
||||
|
||||
if (auto const_gep = llvm::dyn_cast<llvm::Constant>(gep); const_gep) {
|
||||
const_gep = llvm::ConstantExpr::getBitCast(const_gep, goal_ptr_type);
|
||||
return llvm::ConstantExpr::getGetElementPtr(
|
||||
reg->type, const_gep, elem_indexes);
|
||||
return llvm::ConstantExpr::getGetElementPtr(reg->type, const_gep,
|
||||
elem_indexes);
|
||||
|
||||
} else {
|
||||
const auto arr = ir.CreateBitCast(gep, goal_ptr_type);
|
||||
@@ -793,22 +768,20 @@ static llvm::Value *FinishAddressOf(
|
||||
|
||||
// Worst case is that we have to fall down to byte-granularity
|
||||
// pointer arithmetic.
|
||||
const auto byte_type = llvm::IntegerType::getInt8Ty(
|
||||
goal_ptr_type->getContext());
|
||||
const auto byte_type =
|
||||
llvm::IntegerType::getInt8Ty(goal_ptr_type->getContext());
|
||||
llvm::Value *elem_indexes[] = {
|
||||
llvm::ConstantInt::get(index_type, diff, false)
|
||||
};
|
||||
llvm::ConstantInt::get(index_type, diff, false)};
|
||||
|
||||
if (auto const_gep = llvm::dyn_cast<llvm::Constant>(gep); const_gep) {
|
||||
const_gep = llvm::ConstantExpr::getBitCast(
|
||||
const_gep, llvm::PointerType::get(byte_type, addr_space));
|
||||
const_gep = llvm::ConstantExpr::getGetElementPtr(
|
||||
byte_type, const_gep, elem_indexes);
|
||||
const_gep = llvm::ConstantExpr::getGetElementPtr(byte_type, const_gep,
|
||||
elem_indexes);
|
||||
return llvm::ConstantExpr::getBitCast(const_gep, goal_ptr_type);
|
||||
|
||||
} else {
|
||||
gep = ir.CreateBitCast(
|
||||
gep, llvm::PointerType::get(byte_type, addr_space));
|
||||
gep = ir.CreateBitCast(gep, llvm::PointerType::get(byte_type, addr_space));
|
||||
gep = ir.CreateGEP(byte_type, gep, elem_indexes);
|
||||
return ir.CreateBitCast(gep, goal_ptr_type);
|
||||
}
|
||||
@@ -821,13 +794,13 @@ static llvm::Value *FinishAddressOf(
|
||||
llvm::Value *Register::AddressOf(llvm::Value *state_ptr,
|
||||
llvm::BasicBlock *add_to_end) const {
|
||||
CHECK_EQ(&(type->getContext()), &(state_ptr->getContext()));
|
||||
const auto state_ptr_type = llvm::dyn_cast<llvm::PointerType>(
|
||||
state_ptr->getType());
|
||||
const auto state_ptr_type =
|
||||
llvm::dyn_cast<llvm::PointerType>(state_ptr->getType());
|
||||
CHECK_NOTNULL(state_ptr_type);
|
||||
const auto addr_space = state_ptr_type->getAddressSpace();
|
||||
|
||||
const auto state_type = llvm::dyn_cast<llvm::StructType>(
|
||||
state_ptr_type->getPointerElementType());
|
||||
const auto state_type =
|
||||
llvm::dyn_cast<llvm::StructType>(state_ptr_type->getPointerElementType());
|
||||
CHECK_NOTNULL(state_type);
|
||||
|
||||
const auto module = add_to_end->getParent()->getParent();
|
||||
@@ -844,8 +817,8 @@ llvm::Value *Register::AddressOf(llvm::Value *state_ptr,
|
||||
}
|
||||
|
||||
auto state_size = dl.getTypeAllocSize(state_type);
|
||||
return FinishAddressOf(
|
||||
ir, dl, state_ptr_type, state_size, this, addr_space, gep);
|
||||
return FinishAddressOf(ir, dl, state_ptr_type, state_size, this, addr_space,
|
||||
gep);
|
||||
}
|
||||
|
||||
// Converts an LLVM module object to have the right triple / data layout
|
||||
@@ -867,19 +840,14 @@ void Arch::PrepareModuleDataLayout(llvm::Module *mod) const {
|
||||
llvm::AttributeSet target_attribs;
|
||||
target_attribs = target_attribs.addAttribute(
|
||||
context,
|
||||
IF_LLVM_LT_500_(llvm::AttributeSet::FunctionIndex)
|
||||
"target-features");
|
||||
IF_LLVM_LT_500_(llvm::AttributeSet::FunctionIndex) "target-features");
|
||||
target_attribs = target_attribs.addAttribute(
|
||||
context,
|
||||
IF_LLVM_LT_500_(llvm::AttributeSet::FunctionIndex)
|
||||
"target-cpu");
|
||||
context, IF_LLVM_LT_500_(llvm::AttributeSet::FunctionIndex) "target-cpu");
|
||||
|
||||
for (llvm::Function &func : *mod) {
|
||||
auto attribs = func.getAttributes();
|
||||
attribs = attribs.removeAttributes(
|
||||
context,
|
||||
llvm::AttributeLoc::FunctionIndex,
|
||||
target_attribs);
|
||||
context, llvm::AttributeLoc::FunctionIndex, target_attribs);
|
||||
func.setAttributes(attribs);
|
||||
}
|
||||
}
|
||||
@@ -966,8 +934,8 @@ void Arch::CollectRegisters(llvm::Module *module) const {
|
||||
llvm::DataLayout dl(module);
|
||||
const auto basic_block = BasicBlockFunction(module);
|
||||
const auto state_ptr_type = ::remill::StatePointerType(module);
|
||||
const auto state_type = llvm::dyn_cast<llvm::StructType>(
|
||||
state_ptr_type->getElementType());
|
||||
const auto state_type =
|
||||
llvm::dyn_cast<llvm::StructType>(state_ptr_type->getElementType());
|
||||
const auto state_size = dl.getTypeAllocSize(state_type);
|
||||
const auto index_type = llvm::Type::getInt32Ty(module->getContext());
|
||||
|
||||
@@ -1007,8 +975,7 @@ void Arch::CollectRegisters(llvm::Module *module) const {
|
||||
}
|
||||
|
||||
auto name = inst.getName().str();
|
||||
impl->registers.emplace_back(
|
||||
name, offset, dl.getTypeAllocSize(reg_type),
|
||||
impl->registers.emplace_back(name, offset, dl.getTypeAllocSize(reg_type),
|
||||
Complexity(&inst, state_ptr_type), reg_type);
|
||||
|
||||
prev_reg_by_name[name] = &inst;
|
||||
@@ -1036,23 +1003,20 @@ void Arch::CollectRegisters(llvm::Module *module) const {
|
||||
const_cast<Register *>(reg_at_offset)->children.push_back(®);
|
||||
}
|
||||
} else if (!reg_at_offset) {
|
||||
LOG(FATAL)
|
||||
<< "Register " << reg.name << " is not fully enclosed by parent "
|
||||
<< reg.parent->name;
|
||||
LOG(FATAL) << "Register " << reg.name
|
||||
<< " is not fully enclosed by parent " << reg.parent->name;
|
||||
} else if (reg.parent != reg_at_offset) {
|
||||
LOG(FATAL)
|
||||
<< "Can't set parent of register " << reg.name
|
||||
<< " to " << reg_at_offset->name << " because it already has "
|
||||
LOG(FATAL) << "Can't set parent of register " << reg.name << " to "
|
||||
<< reg_at_offset->name << " because it already has "
|
||||
<< reg.parent->name << " as its parent";
|
||||
}
|
||||
reg_at_offset = ®
|
||||
}
|
||||
|
||||
reg.gep_index_list.push_back(
|
||||
llvm::ConstantInt::get(index_type, 0, false));
|
||||
reg.gep_index_list.push_back(llvm::ConstantInt::get(index_type, 0, false));
|
||||
|
||||
std::tie(reg.gep_offset, reg.gep_type_at_offset) = BuildIndexes(
|
||||
dl, state_type, 0, reg.offset, reg.gep_index_list);
|
||||
std::tie(reg.gep_offset, reg.gep_type_at_offset) =
|
||||
BuildIndexes(dl, state_type, 0, reg.offset, reg.gep_index_list);
|
||||
|
||||
CHECK(reg.gep_type_at_offset != nullptr)
|
||||
<< "Unable to create index list for register '" << reg.name << "'";
|
||||
@@ -1060,21 +1024,22 @@ void Arch::CollectRegisters(llvm::Module *module) const {
|
||||
|
||||
auto state_ptr = NthArgument(basic_block, remill::kStatePointerArgNum);
|
||||
|
||||
std::unordered_map<const Register *, llvm::SmallVector<llvm::Value *, 8>> reg_indexes;
|
||||
std::unordered_map<const Register *, llvm::SmallVector<llvm::Value *, 8>>
|
||||
reg_indexes;
|
||||
std::unordered_map<const Register *, llvm::GetElementPtrInst *> reg_gep;
|
||||
|
||||
auto adjust_indexes =
|
||||
[=] (const Register ®, llvm::SmallVector<llvm::Value *, 8> &index_vec) {
|
||||
auto adjust_indexes = [=](const Register ®,
|
||||
llvm::SmallVector<llvm::Value *, 8> &index_vec) {
|
||||
if (!reg.children.empty()) {
|
||||
auto ptr_type = llvm::dyn_cast<llvm::PointerType>(
|
||||
llvm::GetElementPtrInst::getGEPReturnType(
|
||||
state_type, state_ptr, index_vec));
|
||||
llvm::GetElementPtrInst::getGEPReturnType(state_type, state_ptr,
|
||||
index_vec));
|
||||
while (!ptr_type->getElementType()->isStructTy()) {
|
||||
index_vec.pop_back();
|
||||
CHECK(!index_vec.empty());
|
||||
ptr_type = llvm::dyn_cast<llvm::PointerType>(
|
||||
llvm::GetElementPtrInst::getGEPReturnType(
|
||||
state_type, state_ptr, index_vec));
|
||||
llvm::GetElementPtrInst::getGEPReturnType(state_type, state_ptr,
|
||||
index_vec));
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1095,7 +1060,8 @@ void Arch::CollectRegisters(llvm::Module *module) const {
|
||||
auto &parent_indexes = reg_indexes[reg.parent];
|
||||
auto parent_gep = reg_gep[reg.parent];
|
||||
CHECK_NOTNULL(parent_gep);
|
||||
const auto parent_elem_type = parent_gep->getType()->getPointerElementType();
|
||||
const auto parent_elem_type =
|
||||
parent_gep->getType()->getPointerElementType();
|
||||
CHECK(parent_elem_type->isStructTy())
|
||||
<< "Parent register " << reg.parent->name
|
||||
<< " truncated index list isn't pointing to a structure type; got: "
|
||||
@@ -1121,8 +1087,8 @@ void Arch::CollectRegisters(llvm::Module *module) const {
|
||||
std::reverse(sub_indexes.begin(), sub_indexes.end());
|
||||
|
||||
auto gep = llvm::GetElementPtrInst::CreateInBounds(
|
||||
parent_elem_type, parent_gep, sub_indexes, llvm::Twine::createNull(),
|
||||
insert_loc);
|
||||
parent_elem_type, parent_gep, sub_indexes,
|
||||
llvm::Twine::createNull(), insert_loc);
|
||||
|
||||
CHECK_LE(TotalOffset(dl, gep, state_ptr_type), reg.offset);
|
||||
|
||||
@@ -1132,8 +1098,8 @@ void Arch::CollectRegisters(llvm::Module *module) const {
|
||||
} else if (parent_indexes.size() == reg.gep_index_list.size()) {
|
||||
llvm::Value *sub_indices[] = {llvm::ConstantInt::get(index_type, 0)};
|
||||
auto gep = llvm::GetElementPtrInst::CreateInBounds(
|
||||
parent_elem_type, parent_gep, sub_indices, llvm::Twine::createNull(),
|
||||
insert_loc);
|
||||
parent_elem_type, parent_gep, sub_indices,
|
||||
llvm::Twine::createNull(), insert_loc);
|
||||
|
||||
CHECK_LE(TotalOffset(dl, gep, state_ptr_type), reg.offset);
|
||||
|
||||
@@ -1143,8 +1109,7 @@ void Arch::CollectRegisters(llvm::Module *module) const {
|
||||
} else {
|
||||
auto gep = llvm::GetElementPtrInst::CreateInBounds(
|
||||
parent_elem_type, parent_gep, reg.gep_index_list,
|
||||
llvm::Twine::createNull(),
|
||||
insert_loc);
|
||||
llvm::Twine::createNull(), insert_loc);
|
||||
|
||||
CHECK_LE(TotalOffset(dl, gep, state_ptr_type), reg.offset);
|
||||
reg_gep[®] = gep;
|
||||
@@ -1159,8 +1124,8 @@ void Arch::CollectRegisters(llvm::Module *module) const {
|
||||
const auto addr_space = state_ptr_type->getAddressSpace();
|
||||
llvm::IRBuilder<> ir(insert_loc);
|
||||
for (auto ® : impl->registers) {
|
||||
auto final = FinishAddressOf(
|
||||
ir, dl, state_ptr_type, state_size, ®, addr_space, reg_gep[®]);
|
||||
auto final = FinishAddressOf(ir, dl, state_ptr_type, state_size, ®,
|
||||
addr_space, reg_gep[®]);
|
||||
|
||||
auto prev_reg = prev_reg_by_name[reg.name];
|
||||
prev_reg->replaceAllUsesWith(final);
|
||||
@@ -1168,7 +1133,8 @@ void Arch::CollectRegisters(llvm::Module *module) const {
|
||||
final->setName(reg.name);
|
||||
|
||||
// Create the node for a `remill_register` annotation.
|
||||
if (auto final_inst = llvm::dyn_cast<llvm::Instruction>(final); final_inst) {
|
||||
if (auto final_inst = llvm::dyn_cast<llvm::Instruction>(final);
|
||||
final_inst) {
|
||||
#if LLVM_VERSION_NUMBER >= LLVM_VERSION(3, 6)
|
||||
auto reg_name_md = llvm::ValueAsMetadata::get(reg.constant_name);
|
||||
auto reg_name_node = llvm::MDNode::get(*context, reg_name_md);
|
||||
|
||||
+26
-24
@@ -16,17 +16,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <llvm/ADT/SmallVector.h>
|
||||
#include <llvm/ADT/Triple.h>
|
||||
#include <llvm/IR/DataLayout.h>
|
||||
#include <remill/BC/Compat/CallingConvention.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <llvm/ADT/SmallVector.h>
|
||||
#include <llvm/ADT/Triple.h>
|
||||
#include <llvm/IR/DataLayout.h>
|
||||
|
||||
#include <remill/BC/Compat/CallingConvention.h>
|
||||
#include "Instruction.h"
|
||||
|
||||
struct ArchState;
|
||||
@@ -105,8 +105,8 @@ struct Register {
|
||||
|
||||
// Generate a value that will let us load/store to this register, given
|
||||
// a `State *`.
|
||||
llvm::Value *AddressOf(
|
||||
llvm::Value *state_ptr, llvm::BasicBlock *add_to_end) const;
|
||||
llvm::Value *AddressOf(llvm::Value *state_ptr,
|
||||
llvm::BasicBlock *add_to_end) const;
|
||||
|
||||
private:
|
||||
friend class Arch;
|
||||
@@ -125,8 +125,8 @@ class Arch {
|
||||
|
||||
// Factory method for loading the correct architecture class for a given
|
||||
// operating system and architecture class.
|
||||
static const Arch *Get(
|
||||
llvm::LLVMContext &context, OSName os, ArchName arch_name);
|
||||
static const Arch *Get(llvm::LLVMContext &context, OSName os,
|
||||
ArchName arch_name);
|
||||
|
||||
// Return the type of the state structure.
|
||||
llvm::StructType *StateStructType(void) const;
|
||||
@@ -169,19 +169,17 @@ class Arch {
|
||||
// information for the target architecture
|
||||
void PrepareModuleDataLayout(llvm::Module *mod) const;
|
||||
|
||||
inline void PrepareModuleDataLayout(
|
||||
const std::unique_ptr<llvm::Module> &mod) const {
|
||||
inline void
|
||||
PrepareModuleDataLayout(const std::unique_ptr<llvm::Module> &mod) const {
|
||||
PrepareModuleDataLayout(mod.get());
|
||||
}
|
||||
|
||||
// Decode an instruction.
|
||||
virtual bool DecodeInstruction(
|
||||
uint64_t address, std::string_view instr_bytes,
|
||||
virtual bool DecodeInstruction(uint64_t address, std::string_view instr_bytes,
|
||||
Instruction &inst) const = 0;
|
||||
|
||||
// Decode an instruction that is within a delay slot.
|
||||
bool DecodeDelayedInstruction(
|
||||
uint64_t address, std::string_view instr_bytes,
|
||||
bool DecodeDelayedInstruction(uint64_t address, std::string_view instr_bytes,
|
||||
Instruction &inst) const {
|
||||
inst.in_delay_slot = true;
|
||||
return this->DecodeInstruction(address, instr_bytes, inst);
|
||||
@@ -189,8 +187,9 @@ class Arch {
|
||||
|
||||
// Fully decode any control-flow transfer instructions, but only partially
|
||||
// decode other instructions.
|
||||
virtual bool LazyDecodeInstruction(
|
||||
uint64_t address, std::string_view instr_bytes, Instruction &inst) const;
|
||||
virtual bool LazyDecodeInstruction(uint64_t address,
|
||||
std::string_view instr_bytes,
|
||||
Instruction &inst) const;
|
||||
|
||||
// Maximum number of bytes in an instruction for this particular architecture.
|
||||
virtual uint64_t MaxInstructionSize(void) const = 0;
|
||||
@@ -239,7 +238,8 @@ class Arch {
|
||||
bool IsSolaris(void) const;
|
||||
|
||||
// Avoids global cache
|
||||
static ArchPtr Build(llvm::LLVMContext *context, OSName os, ArchName arch_name);
|
||||
static ArchPtr Build(llvm::LLVMContext *context, OSName os,
|
||||
ArchName arch_name);
|
||||
|
||||
// Get the architecture of the modelled code. This is based on command-line
|
||||
// flags. Rather use directly Build.
|
||||
@@ -256,12 +256,12 @@ class Arch {
|
||||
|
||||
private:
|
||||
// Defined in `remill/Arch/X86/Arch.cpp`.
|
||||
static ArchPtr GetX86(
|
||||
llvm::LLVMContext *context, OSName os, ArchName arch_name);
|
||||
static ArchPtr GetX86(llvm::LLVMContext *context, OSName os,
|
||||
ArchName arch_name);
|
||||
|
||||
// Defined in `remill/Arch/AArch64/Arch.cpp`.
|
||||
static ArchPtr GetAArch64(
|
||||
llvm::LLVMContext *context, OSName os, ArchName arch_name);
|
||||
static ArchPtr GetAArch64(llvm::LLVMContext *context, OSName os,
|
||||
ArchName arch_name);
|
||||
|
||||
// Get all of the register information from the prepared module.
|
||||
void CollectRegisters(llvm::Module *module) const;
|
||||
@@ -276,10 +276,12 @@ class Arch {
|
||||
/* Deprecated, do not use, prefer Arch::Build */
|
||||
|
||||
const Arch *GetHostArch(llvm::LLVMContext &context) __attribute__((deprecated));
|
||||
const Arch *GetTargetArch(llvm::LLVMContext &context) __attribute__((deprecated));
|
||||
const Arch *GetTargetArch(llvm::LLVMContext &context)
|
||||
__attribute__((deprecated));
|
||||
|
||||
// Get the architecture of the modelled code. This is based on command-line
|
||||
// flags.
|
||||
const Arch *GetTargetArch(llvm::LLVMContext &context) __attribute__((deprecated));
|
||||
const Arch *GetTargetArch(llvm::LLVMContext &context)
|
||||
__attribute__((deprecated));
|
||||
|
||||
} // namespace remill
|
||||
|
||||
+47
-80
@@ -14,19 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "remill/Arch/Instruction.h"
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
#include "remill/Arch/Arch.h"
|
||||
#include "remill/Arch/Instruction.h"
|
||||
#include "remill/Arch/Name.h"
|
||||
|
||||
namespace remill {
|
||||
|
||||
Operand::Register::Register(void)
|
||||
: size(0) {}
|
||||
Operand::Register::Register(void) : size(0) {}
|
||||
|
||||
Operand::ShiftRegister::ShiftRegister(void)
|
||||
: shift_size(0),
|
||||
@@ -34,9 +34,7 @@ Operand::ShiftRegister::ShiftRegister(void)
|
||||
shift_op(Operand::ShiftRegister::kShiftInvalid),
|
||||
extend_op(Operand::ShiftRegister::kExtendInvalid) {}
|
||||
|
||||
Operand::Immediate::Immediate(void)
|
||||
: val(0),
|
||||
is_signed(false) {}
|
||||
Operand::Immediate::Immediate(void) : val(0), is_signed(false) {}
|
||||
|
||||
Operand::Address::Address(void)
|
||||
: scale(0),
|
||||
@@ -52,14 +50,10 @@ Operand::Operand(void)
|
||||
namespace {
|
||||
static int64_t SignedImmediate(uint64_t val, uint64_t size) {
|
||||
switch (size) {
|
||||
case 8:
|
||||
return static_cast<int64_t>(static_cast<int8_t>(val));
|
||||
case 16:
|
||||
return static_cast<int64_t>(static_cast<int16_t>(val));
|
||||
case 32:
|
||||
return static_cast<int64_t>(static_cast<int32_t>(val));
|
||||
default:
|
||||
return static_cast<int64_t>(val);
|
||||
case 8: return static_cast<int64_t>(static_cast<int8_t>(val));
|
||||
case 16: return static_cast<int64_t>(static_cast<int16_t>(val));
|
||||
case 32: return static_cast<int64_t>(static_cast<int32_t>(val));
|
||||
default: return static_cast<int64_t>(val);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
@@ -67,20 +61,12 @@ static int64_t SignedImmediate(uint64_t val, uint64_t size) {
|
||||
std::string Operand::Serialize(void) const {
|
||||
std::stringstream ss;
|
||||
switch (action) {
|
||||
case Operand::kActionInvalid:
|
||||
ss << "(INVALID_OP ";
|
||||
break;
|
||||
case Operand::kActionRead:
|
||||
ss << "(READ_OP ";
|
||||
break;
|
||||
case Operand::kActionWrite:
|
||||
ss << "(WRITE_OP ";
|
||||
break;
|
||||
case Operand::kActionInvalid: ss << "(INVALID_OP "; break;
|
||||
case Operand::kActionRead: ss << "(READ_OP "; break;
|
||||
case Operand::kActionWrite: ss << "(WRITE_OP "; break;
|
||||
}
|
||||
switch (type) {
|
||||
case Operand::kTypeInvalid:
|
||||
ss << "(INVALID)";
|
||||
break;
|
||||
case Operand::kTypeInvalid: ss << "(INVALID)"; break;
|
||||
|
||||
case Operand::kTypeRegister:
|
||||
ss << "(REG_" << reg.size << " " << reg.name << ")";
|
||||
@@ -89,50 +75,37 @@ std::string Operand::Serialize(void) const {
|
||||
case Operand::kTypeShiftRegister:
|
||||
|
||||
switch (shift_reg.shift_op) {
|
||||
case Operand::ShiftRegister::kShiftInvalid:
|
||||
break;
|
||||
case Operand::ShiftRegister::kShiftInvalid: break;
|
||||
|
||||
case Operand::ShiftRegister::kShiftLeftWithZeroes:
|
||||
ss << "(LSL ";
|
||||
break;
|
||||
case Operand::ShiftRegister::kShiftLeftWithZeroes: ss << "(LSL "; break;
|
||||
|
||||
case Operand::ShiftRegister::kShiftLeftWithOnes:
|
||||
ss << "(MSL ";
|
||||
break;
|
||||
case Operand::ShiftRegister::kShiftLeftWithOnes: ss << "(MSL "; break;
|
||||
|
||||
case Operand::ShiftRegister::kShiftUnsignedRight:
|
||||
ss << "(LSR ";
|
||||
break;
|
||||
case Operand::ShiftRegister::kShiftUnsignedRight: ss << "(LSR "; break;
|
||||
|
||||
case Operand::ShiftRegister::kShiftSignedRight:
|
||||
ss << "(ASR ";
|
||||
break;
|
||||
case Operand::ShiftRegister::kShiftSignedRight: ss << "(ASR "; break;
|
||||
|
||||
case Operand::ShiftRegister::kShiftLeftAround:
|
||||
ss << "(ROL ";
|
||||
break;
|
||||
case Operand::ShiftRegister::kShiftLeftAround: ss << "(ROL "; break;
|
||||
|
||||
case Operand::ShiftRegister::kShiftRightAround:
|
||||
ss << "(ROR ";
|
||||
break;
|
||||
case Operand::ShiftRegister::kShiftRightAround: ss << "(ROR "; break;
|
||||
}
|
||||
|
||||
switch (shift_reg.extend_op) {
|
||||
case Operand::ShiftRegister::kExtendInvalid:
|
||||
ss << "(REG_" << shift_reg.reg.size << " "
|
||||
<< shift_reg.reg.name << ")";
|
||||
ss << "(REG_" << shift_reg.reg.size << " " << shift_reg.reg.name
|
||||
<< ")";
|
||||
break;
|
||||
|
||||
case Operand::ShiftRegister::kExtendSigned:
|
||||
ss << "(SEXT (TRUNC (REG_" << shift_reg.reg.size
|
||||
<< " " << shift_reg.reg.name << ") " << shift_reg.extract_size
|
||||
<< ") " << size << ")";
|
||||
ss << "(SEXT (TRUNC (REG_" << shift_reg.reg.size << " "
|
||||
<< shift_reg.reg.name << ") " << shift_reg.extract_size << ") "
|
||||
<< size << ")";
|
||||
break;
|
||||
|
||||
case Operand::ShiftRegister::kExtendUnsigned:
|
||||
ss << "(ZEXT (TRUNC (REG_" << shift_reg.reg.size
|
||||
<< " " << shift_reg.reg.name << ") " << shift_reg.extract_size
|
||||
<< ") " << size << ")";
|
||||
ss << "(ZEXT (TRUNC (REG_" << shift_reg.reg.size << " "
|
||||
<< shift_reg.reg.name << ") " << shift_reg.extract_size << ") "
|
||||
<< size << ")";
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -172,9 +145,10 @@ std::string Operand::Serialize(void) const {
|
||||
case 512: ss << "QOWORD"; break;
|
||||
default:
|
||||
CHECK(!(size & 7))
|
||||
<< "Memory operand size must be divisible by 8; got "
|
||||
<< size << " bits.";
|
||||
ss << std::dec << (size / 8) << "_BYTES"; break;
|
||||
<< "Memory operand size must be divisible by 8; got " << size
|
||||
<< " bits.";
|
||||
ss << std::dec << (size / 8) << "_BYTES";
|
||||
break;
|
||||
}
|
||||
|
||||
ss << "_PTR";
|
||||
@@ -203,8 +177,8 @@ std::string Operand::Serialize(void) const {
|
||||
}
|
||||
|
||||
if (!addr.base_reg.name.empty()) {
|
||||
ss << " (REG_" << addr.base_reg.size << " "
|
||||
<< addr.base_reg.name << ")";
|
||||
ss << " (REG_" << addr.base_reg.size << " " << addr.base_reg.name
|
||||
<< ")";
|
||||
}
|
||||
|
||||
if (addr.scale) {
|
||||
@@ -213,13 +187,13 @@ std::string Operand::Serialize(void) const {
|
||||
}
|
||||
|
||||
if (!addr.index_reg.name.empty()) {
|
||||
ss << " (REG_" << addr.index_reg.size << " "
|
||||
<< addr.index_reg.name << ")";
|
||||
ss << " (REG_" << addr.index_reg.size << " " << addr.index_reg.name
|
||||
<< ")";
|
||||
}
|
||||
|
||||
if (addr.scale) {
|
||||
ss << " (IMM_" << addr.index_reg.size << " 0x" << std::hex
|
||||
<< addr.scale << std::dec << ")";
|
||||
ss << " (IMM_" << addr.index_reg.size << " 0x" << std::hex << addr.scale
|
||||
<< std::dec << ")";
|
||||
ss << ")"; // End of `(MUL`.
|
||||
}
|
||||
|
||||
@@ -290,21 +264,14 @@ std::string Instruction::Serialize(void) const {
|
||||
std::stringstream ss;
|
||||
ss << "(";
|
||||
switch (arch_name) {
|
||||
case kArchInvalid:
|
||||
break;
|
||||
case kArchInvalid: break;
|
||||
case kArchAMD64:
|
||||
case kArchAMD64_AVX:
|
||||
case kArchAMD64_AVX512:
|
||||
ss << "AMD64";
|
||||
break;
|
||||
case kArchAMD64_AVX512: ss << "AMD64"; break;
|
||||
case kArchX86:
|
||||
case kArchX86_AVX:
|
||||
case kArchX86_AVX512:
|
||||
ss << "X86";
|
||||
break;
|
||||
case kArchAArch64LittleEndian:
|
||||
ss << "AArch64";
|
||||
break;
|
||||
case kArchX86_AVX512: ss << "X86"; break;
|
||||
case kArchAArch64LittleEndian: ss << "AArch64"; break;
|
||||
}
|
||||
|
||||
ss << " " << std::hex << pc;
|
||||
@@ -316,8 +283,8 @@ std::string Instruction::Serialize(void) const {
|
||||
} else {
|
||||
ss << " (BYTES";
|
||||
for (auto byte : bytes) {
|
||||
ss << " " << std::setw(2) << std::setfill('0')
|
||||
<< std::hex << static_cast<unsigned>(static_cast<uint8_t>(byte));
|
||||
ss << " " << std::setw(2) << std::setfill('0') << std::hex
|
||||
<< static_cast<unsigned>(static_cast<uint8_t>(byte));
|
||||
}
|
||||
ss << ")";
|
||||
}
|
||||
@@ -326,12 +293,13 @@ std::string Instruction::Serialize(void) const {
|
||||
ss << " (NO-BYTES)";
|
||||
|
||||
} else {
|
||||
|
||||
// if the instruction is invalid print the bytes
|
||||
// It will be helpful in mapping to the instruction in the absence of binary
|
||||
ss << " (BYTES";
|
||||
for (auto byte : bytes) {
|
||||
ss << " " << std::setw(2) << std::setfill('0')
|
||||
<< std::hex << static_cast<unsigned>(static_cast<uint8_t>(byte));
|
||||
ss << " " << std::setw(2) << std::setfill('0') << std::hex
|
||||
<< static_cast<unsigned>(static_cast<uint8_t>(byte));
|
||||
}
|
||||
ss << ")";
|
||||
}
|
||||
@@ -381,8 +349,7 @@ std::string Instruction::Serialize(void) const {
|
||||
ss << " (COND_BRANCH (TAKEN " << std::hex << branch_taken_pc << ")"
|
||||
<< " (NOT_TAKEN " << branch_not_taken_pc << std::dec << "))";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
ss << ")";
|
||||
|
||||
@@ -39,11 +39,7 @@ class Operand {
|
||||
kTypeAddress
|
||||
} type;
|
||||
|
||||
enum Action {
|
||||
kActionInvalid,
|
||||
kActionRead,
|
||||
kActionWrite
|
||||
} action;
|
||||
enum Action { kActionInvalid, kActionRead, kActionWrite } action;
|
||||
|
||||
// Size of this operand, in bits.
|
||||
uint64_t size;
|
||||
@@ -200,10 +196,8 @@ class Instruction {
|
||||
switch (category) {
|
||||
case kCategoryInvalid:
|
||||
case kCategoryNormal:
|
||||
case kCategoryNoOp:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
case kCategoryNoOp: return false;
|
||||
default: return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,10 +205,8 @@ class Instruction {
|
||||
switch (category) {
|
||||
case kCategoryDirectFunctionCall:
|
||||
case kCategoryDirectJump:
|
||||
case kCategoryConditionalBranch:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
case kCategoryConditionalBranch: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,10 +217,8 @@ class Instruction {
|
||||
case kCategoryConditionalBranch:
|
||||
case kCategoryAsyncHyperCall:
|
||||
case kCategoryConditionalAsyncHyperCall:
|
||||
case kCategoryFunctionReturn:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
case kCategoryFunctionReturn: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,10 +229,8 @@ class Instruction {
|
||||
inline bool IsFunctionCall(void) const {
|
||||
switch (category) {
|
||||
case kCategoryDirectFunctionCall:
|
||||
case kCategoryIndirectFunctionCall:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
case kCategoryIndirectFunctionCall: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-24
@@ -22,14 +22,10 @@ namespace remill {
|
||||
|
||||
ArchName GetArchName(const llvm::Triple &triple) {
|
||||
switch (triple.getArch()) {
|
||||
case llvm::Triple::ArchType::x86:
|
||||
return kArchX86;
|
||||
case llvm::Triple::ArchType::x86_64:
|
||||
return kArchAMD64;
|
||||
case llvm::Triple::ArchType::aarch64:
|
||||
return kArchAArch64LittleEndian;
|
||||
default:
|
||||
return kArchInvalid;
|
||||
case llvm::Triple::ArchType::x86: return kArchX86;
|
||||
case llvm::Triple::ArchType::x86_64: return kArchAMD64;
|
||||
case llvm::Triple::ArchType::aarch64: return kArchAArch64LittleEndian;
|
||||
default: return kArchInvalid;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,22 +58,14 @@ ArchName GetArchName(const std::string &arch_name) {
|
||||
|
||||
std::string GetArchName(ArchName arch_name) {
|
||||
switch (arch_name) {
|
||||
case kArchInvalid:
|
||||
return "invalid";
|
||||
case kArchX86:
|
||||
return "x86";
|
||||
case kArchX86_AVX:
|
||||
return "x86_avx";
|
||||
case kArchX86_AVX512:
|
||||
return "x86_avx512";
|
||||
case kArchAMD64:
|
||||
return "amd64";
|
||||
case kArchAMD64_AVX:
|
||||
return "amd64_avx";
|
||||
case kArchAMD64_AVX512:
|
||||
return "amd64_avx512";
|
||||
case kArchAArch64LittleEndian:
|
||||
return "aarch64";
|
||||
case kArchInvalid: return "invalid";
|
||||
case kArchX86: return "x86";
|
||||
case kArchX86_AVX: return "x86_avx";
|
||||
case kArchX86_AVX512: return "x86_avx512";
|
||||
case kArchAMD64: return "amd64";
|
||||
case kArchAMD64_AVX: return "amd64_avx";
|
||||
case kArchAMD64_AVX512: return "amd64_avx512";
|
||||
case kArchAArch64LittleEndian: return "aarch64";
|
||||
}
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
@@ -43,19 +43,15 @@
|
||||
#endif
|
||||
|
||||
// Attributes that will force inlining of specific code.
|
||||
#define ALWAYS_INLINE \
|
||||
[[gnu::always_inline]] \
|
||||
inline
|
||||
#define ALWAYS_INLINE [[gnu::always_inline]] inline
|
||||
|
||||
#define NEVER_INLINE [[gnu::noinline]]
|
||||
|
||||
// Define a specific instruction selection variable.
|
||||
#define DEF_ISEL(name) \
|
||||
extern "C" constexpr auto ISEL_ ## name [[gnu::used]]
|
||||
#define DEF_ISEL(name) extern "C" constexpr auto ISEL_##name [[gnu::used]]
|
||||
|
||||
// Define a conditional execution function.
|
||||
#define DEF_COND(name) \
|
||||
extern "C" constexpr auto COND_ ## name [[gnu::used]]
|
||||
#define DEF_COND(name) extern "C" constexpr auto COND_##name [[gnu::used]]
|
||||
|
||||
// Define a semantics implementing function.
|
||||
#define DEF_SEM(name, ...) \
|
||||
@@ -105,97 +101,86 @@
|
||||
#define DEF_ISEL_Rn(name, tpl_func) \
|
||||
DEF_ISEL(name##_8) = tpl_func<R8>; \
|
||||
DEF_ISEL(name##_16) = tpl_func<R16>; \
|
||||
DEF_ISEL(name ## _32) = tpl_func<R32> \
|
||||
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<R64> )
|
||||
DEF_ISEL(name##_32) = \
|
||||
tpl_func<R32> IF_64BIT(; DEF_ISEL(name##_64) = tpl_func<R64>)
|
||||
|
||||
// An instruction with a single, explicit destination operand (register).
|
||||
#define DEF_ISEL_RnW(name, tpl_func) \
|
||||
DEF_ISEL(name##_8) = tpl_func<R8W>; \
|
||||
DEF_ISEL(name##_16) = tpl_func<R16W>; \
|
||||
DEF_ISEL(name ## _32) = tpl_func<R32W> \
|
||||
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<R64W> )
|
||||
DEF_ISEL(name##_32) = \
|
||||
tpl_func<R32W> IF_64BIT(; DEF_ISEL(name##_64) = tpl_func<R64W>)
|
||||
|
||||
// An instruction with a single, explicit source operand (memory).
|
||||
#define DEF_ISEL_Mn(name, tpl_func) \
|
||||
DEF_ISEL(name##_8) = tpl_func<M8>; \
|
||||
DEF_ISEL(name##_16) = tpl_func<M16>; \
|
||||
DEF_ISEL(name ## _32) = tpl_func<M32> \
|
||||
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<M64> )
|
||||
DEF_ISEL(name##_32) = \
|
||||
tpl_func<M32> IF_64BIT(; DEF_ISEL(name##_64) = tpl_func<M64>)
|
||||
|
||||
// An instruction with a single, explicit destination operand (memory).
|
||||
#define DEF_ISEL_MnW(name, tpl_func) \
|
||||
DEF_ISEL(name##_8) = tpl_func<M8W>; \
|
||||
DEF_ISEL(name##_16) = tpl_func<M16W>; \
|
||||
DEF_ISEL(name ## _32) = tpl_func<M32W> \
|
||||
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<M64W> )
|
||||
DEF_ISEL(name##_32) = \
|
||||
tpl_func<M32W> IF_64BIT(; DEF_ISEL(name##_64) = tpl_func<M64W>)
|
||||
|
||||
// An instruction with no explicit destination operand and an immediate source.
|
||||
#define DEF_ISEL_In(name, tpl_func) \
|
||||
DEF_ISEL(name##_8) = tpl_func<I8>; \
|
||||
DEF_ISEL(name##_16) = tpl_func<I16>; \
|
||||
DEF_ISEL(name ## _32) = tpl_func<I32> \
|
||||
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<I64> )
|
||||
DEF_ISEL(name##_32) = \
|
||||
tpl_func<I32> IF_64BIT(; DEF_ISEL(name##_64) = tpl_func<I64>)
|
||||
|
||||
// Two source operand instruction
|
||||
#define _DEF_ISEL_Xn_Yn(X, Y, name, tpl_func) \
|
||||
DEF_ISEL(name##_8) = tpl_func<X##8, Y##8>; \
|
||||
DEF_ISEL(name##_16) = tpl_func<X##16, Y##16>; \
|
||||
DEF_ISEL(name ## _32) = tpl_func<X ## 32, Y ## 32> \
|
||||
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<X ## 64, Y ## 64> )
|
||||
DEF_ISEL(name##_32) = tpl_func<X##32, Y##32> IF_64BIT( \
|
||||
; DEF_ISEL(name##_64) = tpl_func<X##64, Y##64>)
|
||||
|
||||
|
||||
#define DEF_ISEL_Rn_Mn(name, tpl_func) \
|
||||
_DEF_ISEL_Xn_Yn(R, M, name, tpl_func)
|
||||
#define DEF_ISEL_Rn_Mn(name, tpl_func) _DEF_ISEL_Xn_Yn(R, M, name, tpl_func)
|
||||
|
||||
#define DEF_ISEL_Rn_Rn(name, tpl_func) \
|
||||
_DEF_ISEL_Xn_Yn(R, R, name, tpl_func)
|
||||
#define DEF_ISEL_Rn_Rn(name, tpl_func) _DEF_ISEL_Xn_Yn(R, R, name, tpl_func)
|
||||
|
||||
#define DEF_ISEL_Rn_In(name, tpl_func) \
|
||||
_DEF_ISEL_Xn_Yn(R, I, name, tpl_func)
|
||||
#define DEF_ISEL_Rn_In(name, tpl_func) _DEF_ISEL_Xn_Yn(R, I, name, tpl_func)
|
||||
|
||||
#define DEF_ISEL_Mn_In(name, tpl_func) \
|
||||
_DEF_ISEL_Xn_Yn(M, I, name, tpl_func)
|
||||
#define DEF_ISEL_Mn_In(name, tpl_func) _DEF_ISEL_Xn_Yn(M, I, name, tpl_func)
|
||||
|
||||
#define DEF_ISEL_Mn_Rn(name, tpl_func) \
|
||||
_DEF_ISEL_Xn_Yn(M, R, name, tpl_func)
|
||||
#define DEF_ISEL_Mn_Rn(name, tpl_func) _DEF_ISEL_Xn_Yn(M, R, name, tpl_func)
|
||||
|
||||
// One destination, one source operand instruction.
|
||||
#define _DEF_ISEL_XnW_Yn(X, Y, name, tpl_func) \
|
||||
DEF_ISEL(name##_8) = tpl_func<X##8W, Y##8>; \
|
||||
DEF_ISEL(name##_16) = tpl_func<X##16W, Y##16>; \
|
||||
DEF_ISEL(name ## _32) = tpl_func<X ## 32W, Y ## 32> \
|
||||
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<X ## 64W, Y ## 64> )
|
||||
DEF_ISEL(name##_32) = tpl_func<X##32W, Y##32> IF_64BIT( \
|
||||
; DEF_ISEL(name##_64) = tpl_func<X##64W, Y##64>)
|
||||
|
||||
#define DEF_ISEL_RnW_Mn(name, tpl_func) \
|
||||
_DEF_ISEL_XnW_Yn(R, M, name, tpl_func)
|
||||
#define DEF_ISEL_RnW_Mn(name, tpl_func) _DEF_ISEL_XnW_Yn(R, M, name, tpl_func)
|
||||
|
||||
#define DEF_ISEL_RnW_Rn(name, tpl_func) \
|
||||
_DEF_ISEL_XnW_Yn(R, R, name, tpl_func)
|
||||
#define DEF_ISEL_RnW_Rn(name, tpl_func) _DEF_ISEL_XnW_Yn(R, R, name, tpl_func)
|
||||
|
||||
#define DEF_ISEL_RnW_In(name, tpl_func) \
|
||||
_DEF_ISEL_XnW_Yn(R, I, name, tpl_func)
|
||||
#define DEF_ISEL_RnW_In(name, tpl_func) _DEF_ISEL_XnW_Yn(R, I, name, tpl_func)
|
||||
|
||||
#define DEF_ISEL_MnW_In(name, tpl_func) \
|
||||
_DEF_ISEL_XnW_Yn(M, I, name, tpl_func)
|
||||
#define DEF_ISEL_MnW_In(name, tpl_func) _DEF_ISEL_XnW_Yn(M, I, name, tpl_func)
|
||||
|
||||
#define DEF_ISEL_MnW_Rn(name, tpl_func) \
|
||||
_DEF_ISEL_XnW_Yn(M, R, name, tpl_func)
|
||||
#define DEF_ISEL_MnW_Rn(name, tpl_func) _DEF_ISEL_XnW_Yn(M, R, name, tpl_func)
|
||||
|
||||
#define DEF_ISEL_MnW_Mn(name, tpl_func) \
|
||||
_DEF_ISEL_XnW_Yn(M, M, name, tpl_func)
|
||||
#define DEF_ISEL_MnW_Mn(name, tpl_func) _DEF_ISEL_XnW_Yn(M, M, name, tpl_func)
|
||||
|
||||
// One destination, two source operand instruction
|
||||
#define _DEF_ISEL_XnW_Yn_Zn(X, Y, Z, name, tpl_func) \
|
||||
DEF_ISEL(name##_8) = tpl_func<X##8W, Y##8, Z##8>; \
|
||||
DEF_ISEL(name##_16) = tpl_func<X##16W, Y##16, Z##16>; \
|
||||
DEF_ISEL(name ## _32) = tpl_func<X ## 32W, Y ## 32, Z ## 32> \
|
||||
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<X ## 64W, Y ## 64, Z ## 64> )
|
||||
DEF_ISEL(name##_32) = tpl_func<X##32W, Y##32, Z##32> IF_64BIT( \
|
||||
; DEF_ISEL(name##_64) = tpl_func<X##64W, Y##64, Z##64>)
|
||||
|
||||
#define _DEF_ISEL_XnW_Xn_Yn_Zn(X, Y, Z, name, tpl_func) \
|
||||
DEF_ISEL(name##_8) = tpl_func<X##8W, X##8, Y##8, Z##8>; \
|
||||
DEF_ISEL(name##_16) = tpl_func<X##16W, X##16, Y##16, Z##16>; \
|
||||
DEF_ISEL(name ## _32) = tpl_func<X ## 32W, X ## 32, Y ## 32, Z ## 32> \
|
||||
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<X ## 64W, X ## 64, Y ## 64, Z ## 64> )
|
||||
DEF_ISEL(name##_32) = tpl_func<X##32W, X##32, Y##32, Z##32> IF_64BIT( \
|
||||
; DEF_ISEL(name##_64) = tpl_func<X##64W, X##64, Y##64, Z##64>)
|
||||
|
||||
#define DEF_ISEL_RnW_Rn_Mn(name, tpl_func) \
|
||||
_DEF_ISEL_XnW_Yn_Zn(R, R, M, name, tpl_func)
|
||||
@@ -211,8 +196,8 @@
|
||||
#define _DEF_ISEL_XnW_Xn_YnW_Yn(X, Y, name, tpl_func) \
|
||||
DEF_ISEL(name##_8) = tpl_func<X##8W, X##8, Y##8W, Y##8>; \
|
||||
DEF_ISEL(name##_16) = tpl_func<X##16W, X##16, Y##16W, Y##16>; \
|
||||
DEF_ISEL(name ## _32) = tpl_func<X ## 32W, X ## 32, Y ## 32W, Y ## 32> \
|
||||
IF_64BIT( ; DEF_ISEL(name ## _64) = tpl_func<X ## 64W, X ## 64, Y ## 64W, Y ## 64> )
|
||||
DEF_ISEL(name##_32) = tpl_func<X##32W, X##32, Y##32W, Y##32> IF_64BIT( \
|
||||
; DEF_ISEL(name##_64) = tpl_func<X##64W, X##64, Y##64W, Y##64>)
|
||||
|
||||
#define DEF_ISEL_MnW_Mn_RnW_Rn(name, tpl_func) \
|
||||
_DEF_ISEL_XnW_Xn_YnW_Yn(M, R, name, tpl_func)
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "remill/Arch/Runtime/Intrinsics.h"
|
||||
|
||||
#include "remill/Arch/Runtime/Operators.h"
|
||||
|
||||
#define USED(sym) \
|
||||
__remill_mark_as_used(reinterpret_cast<const void *>(&sym))
|
||||
#define USED(sym) __remill_mark_as_used(reinterpret_cast<const void *>(&sym))
|
||||
|
||||
// This is two big hacks:
|
||||
// 1) This makes sure that a symbol is treated as used and prevents it
|
||||
@@ -31,8 +31,7 @@ extern "C" void __remill_mark_as_used(const void *);
|
||||
|
||||
// This is just a hack to make sure all these functions appear in the bitcode
|
||||
// file!
|
||||
[[gnu::used]]
|
||||
extern "C" void __remill_intrinsics(void) {
|
||||
[[gnu::used]] extern "C" void __remill_intrinsics(void) {
|
||||
|
||||
USED(__remill_basic_block);
|
||||
|
||||
|
||||
+138
-149
@@ -16,137 +16,121 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "remill/Arch/Runtime/Types.h"
|
||||
#include "remill/Arch/Runtime/HyperCall.h"
|
||||
#include "remill/Arch/Runtime/Types.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
// The basic block "template".
|
||||
[[gnu::used]]
|
||||
Memory *__remill_basic_block(State &state, addr_t pc, Memory *memory);
|
||||
[[gnu::used]] Memory *__remill_basic_block(State &state, addr_t pc,
|
||||
Memory *memory);
|
||||
|
||||
// Memory read intrinsics.
|
||||
[[gnu::used, gnu::const]]
|
||||
extern uint8_t __remill_read_memory_8(Memory *, addr_t);
|
||||
[[gnu::used, gnu::const]] extern uint8_t __remill_read_memory_8(Memory *,
|
||||
addr_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern uint16_t __remill_read_memory_16(Memory *, addr_t);
|
||||
[[gnu::used, gnu::const]] extern uint16_t __remill_read_memory_16(Memory *,
|
||||
addr_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern uint32_t __remill_read_memory_32(Memory *, addr_t);
|
||||
[[gnu::used, gnu::const]] extern uint32_t __remill_read_memory_32(Memory *,
|
||||
addr_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern uint64_t __remill_read_memory_64(Memory *, addr_t);
|
||||
[[gnu::used, gnu::const]] extern uint64_t __remill_read_memory_64(Memory *,
|
||||
addr_t);
|
||||
|
||||
// Memory write intrinsics.
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_write_memory_8(Memory *, addr_t, uint8_t);
|
||||
[[gnu::used, gnu::const]] extern Memory *
|
||||
__remill_write_memory_8(Memory *, addr_t, uint8_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_write_memory_16(Memory *, addr_t, uint16_t);
|
||||
[[gnu::used, gnu::const]] extern Memory *
|
||||
__remill_write_memory_16(Memory *, addr_t, uint16_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_write_memory_32(Memory *, addr_t, uint32_t);
|
||||
[[gnu::used, gnu::const]] extern Memory *
|
||||
__remill_write_memory_32(Memory *, addr_t, uint32_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_write_memory_64(Memory *, addr_t, uint64_t);
|
||||
[[gnu::used, gnu::const]] extern Memory *
|
||||
__remill_write_memory_64(Memory *, addr_t, uint64_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern float32_t __remill_read_memory_f32(Memory *, addr_t);
|
||||
[[gnu::used, gnu::const]] extern float32_t __remill_read_memory_f32(Memory *,
|
||||
addr_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern float64_t __remill_read_memory_f64(Memory *, addr_t);
|
||||
[[gnu::used, gnu::const]] extern float64_t __remill_read_memory_f64(Memory *,
|
||||
addr_t);
|
||||
|
||||
[[gnu::used]]
|
||||
extern float64_t __remill_read_memory_f80(Memory *, addr_t);
|
||||
[[gnu::used]] extern float64_t __remill_read_memory_f80(Memory *, addr_t);
|
||||
|
||||
[[gnu::used]]
|
||||
extern float64_t __remill_read_memory_f128(Memory *, addr_t);
|
||||
[[gnu::used]] extern float64_t __remill_read_memory_f128(Memory *, addr_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_write_memory_f32(Memory *, addr_t, float32_t);
|
||||
[[gnu::used, gnu::const]] extern Memory *
|
||||
__remill_write_memory_f32(Memory *, addr_t, float32_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_write_memory_f64(Memory *, addr_t, float64_t);
|
||||
[[gnu::used, gnu::const]] extern Memory *
|
||||
__remill_write_memory_f64(Memory *, addr_t, float64_t);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_write_memory_f80(Memory *, addr_t, float64_t);
|
||||
[[gnu::used]] extern Memory *__remill_write_memory_f80(Memory *, addr_t,
|
||||
float64_t);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_write_memory_f128(Memory *, addr_t, float64_t);
|
||||
[[gnu::used]] extern Memory *__remill_write_memory_f128(Memory *, addr_t,
|
||||
float64_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern uint8_t __remill_undefined_8(void);
|
||||
[[gnu::used, gnu::const]] extern uint8_t __remill_undefined_8(void);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern uint16_t __remill_undefined_16(void);
|
||||
[[gnu::used, gnu::const]] extern uint16_t __remill_undefined_16(void);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern uint32_t __remill_undefined_32(void);
|
||||
[[gnu::used, gnu::const]] extern uint32_t __remill_undefined_32(void);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern uint64_t __remill_undefined_64(void);
|
||||
[[gnu::used, gnu::const]] extern uint64_t __remill_undefined_64(void);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern float32_t __remill_undefined_f32(void);
|
||||
[[gnu::used, gnu::const]] extern float32_t __remill_undefined_f32(void);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern float64_t __remill_undefined_f64(void);
|
||||
[[gnu::used, gnu::const]] extern float64_t __remill_undefined_f64(void);
|
||||
|
||||
// Generic error.
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_error(State &, addr_t addr, Memory *);
|
||||
[[gnu::used]] extern Memory *__remill_error(State &, addr_t addr, Memory *);
|
||||
|
||||
// Control-flow intrinsics.
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_function_call(State &, addr_t addr, Memory *);
|
||||
[[gnu::used]] extern Memory *__remill_function_call(State &, addr_t addr,
|
||||
Memory *);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_function_return(State &, addr_t addr, Memory *);
|
||||
[[gnu::used]] extern Memory *__remill_function_return(State &, addr_t addr,
|
||||
Memory *);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_jump(State &, addr_t addr, Memory *);
|
||||
[[gnu::used]] extern Memory *__remill_jump(State &, addr_t addr, Memory *);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_missing_block(State &, addr_t addr, Memory *);
|
||||
[[gnu::used]] extern Memory *__remill_missing_block(State &, addr_t addr,
|
||||
Memory *);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_async_hyper_call(State &, addr_t ret_addr, Memory *);
|
||||
[[gnu::used]] extern Memory *__remill_async_hyper_call(State &, addr_t ret_addr,
|
||||
Memory *);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_sync_hyper_call(State &, Memory *, SyncHyperCall::Name);
|
||||
[[gnu::used]] extern Memory *__remill_sync_hyper_call(State &, Memory *,
|
||||
SyncHyperCall::Name);
|
||||
|
||||
// Memory barriers types:
|
||||
// http://g.oswego.edu/dl/jmm/cookbook.html
|
||||
// http://preshing.com/20120913/acquire-and-release-semantics/
|
||||
// http://preshing.com/20120710/memory-barriers-are-like-source-control-operations/
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_barrier_load_load(Memory *);
|
||||
[[gnu::used, gnu::const]] extern Memory *__remill_barrier_load_load(Memory *);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_barrier_load_store(Memory *); // Load acquire.
|
||||
[[gnu::used, gnu::const]] extern Memory *
|
||||
__remill_barrier_load_store(Memory *); // Load acquire.
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_barrier_store_load(Memory *);
|
||||
[[gnu::used, gnu::const]] extern Memory *__remill_barrier_store_load(Memory *);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_barrier_store_store(Memory *); // Store release.
|
||||
[[gnu::used, gnu::const]] extern Memory *
|
||||
__remill_barrier_store_store(Memory *); // Store release.
|
||||
|
||||
// Atomic operations. The address/size are hints, but the granularity of the
|
||||
// access can be bigger. These have implicit StoreLoad semantics.
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_atomic_begin(Memory *);
|
||||
[[gnu::used, gnu::const]] extern Memory *__remill_atomic_begin(Memory *);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_atomic_end(Memory *);
|
||||
[[gnu::used, gnu::const]] extern Memory *__remill_atomic_end(Memory *);
|
||||
|
||||
// Used to signal the begin/ending of an instruction executed within a delay
|
||||
// slot.
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_delay_slot_begin(Memory *);
|
||||
[[gnu::used, gnu::const]] extern Memory *__remill_delay_slot_begin(Memory *);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_delay_slot_end(Memory *);
|
||||
[[gnu::used, gnu::const]] extern Memory *__remill_delay_slot_end(Memory *);
|
||||
|
||||
/* Most memory intrinsics are marked as `[[gnu::const]]` which tells the compiler that they
|
||||
* do not read/write to memory. This permits LLVM to optimize around the intrinsic, without thinking
|
||||
@@ -162,92 +146,97 @@ extern Memory *__remill_delay_slot_end(Memory *);
|
||||
*/
|
||||
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_compare_exchange_memory_8(Memory *, addr_t addr, uint8_t &expected, uint8_t desired);
|
||||
[[gnu::used]] extern Memory *
|
||||
__remill_compare_exchange_memory_8(Memory *, addr_t addr, uint8_t &expected,
|
||||
uint8_t desired);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_compare_exchange_memory_16(Memory *, addr_t addr, uint16_t &expected, uint16_t desired);
|
||||
[[gnu::used]] extern Memory *
|
||||
__remill_compare_exchange_memory_16(Memory *, addr_t addr, uint16_t &expected,
|
||||
uint16_t desired);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_compare_exchange_memory_32(Memory *, addr_t addr, uint32_t &expected, uint32_t desired);
|
||||
[[gnu::used]] extern Memory *
|
||||
__remill_compare_exchange_memory_32(Memory *, addr_t addr, uint32_t &expected,
|
||||
uint32_t desired);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_compare_exchange_memory_64(Memory *, addr_t addr, uint64_t &expected, uint64_t desired);
|
||||
[[gnu::used]] extern Memory *
|
||||
__remill_compare_exchange_memory_64(Memory *, addr_t addr, uint64_t &expected,
|
||||
uint64_t desired);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_compare_exchange_memory_128(Memory *, addr_t addr, uint128_t &expected, uint128_t &desired);
|
||||
[[gnu::used]] extern Memory *
|
||||
__remill_compare_exchange_memory_128(Memory *, addr_t addr, uint128_t &expected,
|
||||
uint128_t &desired);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_add_8(Memory *, addr_t addr, uint8_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_add_8(Memory *, addr_t addr,
|
||||
uint8_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_add_16(Memory *, addr_t addr, uint16_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_add_16(Memory *, addr_t addr,
|
||||
uint16_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_add_32(Memory *, addr_t addr, uint32_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_add_32(Memory *, addr_t addr,
|
||||
uint32_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_add_64(Memory *, addr_t addr, uint64_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_add_64(Memory *, addr_t addr,
|
||||
uint64_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_sub_8(Memory *, addr_t addr, uint8_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_sub_8(Memory *, addr_t addr,
|
||||
uint8_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_sub_16(Memory *, addr_t addr, uint16_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_sub_16(Memory *, addr_t addr,
|
||||
uint16_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_sub_32(Memory *, addr_t addr, uint32_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_sub_32(Memory *, addr_t addr,
|
||||
uint32_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_sub_64(Memory *, addr_t addr, uint64_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_sub_64(Memory *, addr_t addr,
|
||||
uint64_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_and_8(Memory *, addr_t addr, uint8_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_and_8(Memory *, addr_t addr,
|
||||
uint8_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_and_16(Memory *, addr_t addr, uint16_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_and_16(Memory *, addr_t addr,
|
||||
uint16_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_and_32(Memory *, addr_t addr, uint32_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_and_32(Memory *, addr_t addr,
|
||||
uint32_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_and_64(Memory *, addr_t addr, uint64_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_and_64(Memory *, addr_t addr,
|
||||
uint64_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_or_8(Memory *, addr_t addr, uint8_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_or_8(Memory *, addr_t addr,
|
||||
uint8_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_or_16(Memory *, addr_t addr, uint16_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_or_16(Memory *, addr_t addr,
|
||||
uint16_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_or_32(Memory *, addr_t addr, uint32_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_or_32(Memory *, addr_t addr,
|
||||
uint32_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_or_64(Memory *, addr_t addr, uint64_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_or_64(Memory *, addr_t addr,
|
||||
uint64_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_xor_8(Memory *, addr_t addr, uint8_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_xor_8(Memory *, addr_t addr,
|
||||
uint8_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_xor_16(Memory *, addr_t addr, uint16_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_xor_16(Memory *, addr_t addr,
|
||||
uint16_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_xor_32(Memory *, addr_t addr, uint32_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_xor_32(Memory *, addr_t addr,
|
||||
uint32_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_xor_64(Memory *, addr_t addr, uint64_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_xor_64(Memory *, addr_t addr,
|
||||
uint64_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_nand_8(Memory *, addr_t addr, uint8_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_nand_8(Memory *, addr_t addr,
|
||||
uint8_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_nand_16(Memory *, addr_t addr, uint16_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_nand_16(Memory *, addr_t addr,
|
||||
uint16_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_nand_32(Memory *, addr_t addr, uint32_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_nand_32(Memory *, addr_t addr,
|
||||
uint32_t &value);
|
||||
|
||||
[[gnu::used]]
|
||||
extern Memory *__remill_fetch_and_nand_64(Memory *, addr_t addr, uint64_t &value);
|
||||
[[gnu::used]] extern Memory *__remill_fetch_and_nand_64(Memory *, addr_t addr,
|
||||
uint64_t &value);
|
||||
|
||||
// Read and modify the floating point exception state of the (virtual) machine
|
||||
// that is executing the actual floating point operations.
|
||||
@@ -258,26 +247,26 @@ extern Memory *__remill_fetch_and_nand_64(Memory *, addr_t addr, uint64_t &value
|
||||
// auto flags = __remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, 0);
|
||||
//
|
||||
// These flags are also subject to optimizations
|
||||
[[gnu::used, gnu::const]]
|
||||
extern int __remill_fpu_exception_test_and_clear(int read_mask, int clear_mask);
|
||||
[[gnu::used, gnu::const]] extern int
|
||||
__remill_fpu_exception_test_and_clear(int read_mask, int clear_mask);
|
||||
|
||||
// Read/write to I/O ports.
|
||||
[[gnu::used, gnu::const]]
|
||||
extern uint8_t __remill_read_io_port_8(Memory *, addr_t);
|
||||
[[gnu::used, gnu::const]] extern uint8_t __remill_read_io_port_8(Memory *,
|
||||
addr_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern uint16_t __remill_read_io_port_16(Memory *, addr_t);
|
||||
[[gnu::used, gnu::const]] extern uint16_t __remill_read_io_port_16(Memory *,
|
||||
addr_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern uint32_t __remill_read_io_port_32(Memory *, addr_t);
|
||||
[[gnu::used, gnu::const]] extern uint32_t __remill_read_io_port_32(Memory *,
|
||||
addr_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_write_io_port_8(Memory *, addr_t, uint8_t);
|
||||
[[gnu::used, gnu::const]] extern Memory *
|
||||
__remill_write_io_port_8(Memory *, addr_t, uint8_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_write_io_port_16(Memory *, addr_t, uint16_t);
|
||||
[[gnu::used, gnu::const]] extern Memory *
|
||||
__remill_write_io_port_16(Memory *, addr_t, uint16_t);
|
||||
|
||||
[[gnu::used, gnu::const]]
|
||||
extern Memory *__remill_write_io_port_32(Memory *, addr_t, uint32_t);
|
||||
[[gnu::used, gnu::const]] extern Memory *
|
||||
__remill_write_io_port_32(Memory *, addr_t, uint32_t);
|
||||
|
||||
} // extern C
|
||||
|
||||
+212
-319
File diff suppressed because it is too large
Load Diff
@@ -16,8 +16,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "remill/Arch/Runtime/Definitions.h"
|
||||
#include "remill/Arch/Runtime/Intrinsics.h"
|
||||
#include "remill/Arch/Runtime/Operators.h"
|
||||
#include "remill/Arch/Runtime/Types.h"
|
||||
#include "remill/Arch/Runtime/State.h"
|
||||
#include "remill/Arch/Runtime/Definitions.h"
|
||||
#include "remill/Arch/Runtime/Types.h"
|
||||
|
||||
+13
-20
@@ -168,9 +168,7 @@ union vec512_t;
|
||||
\
|
||||
template <> \
|
||||
struct VectorType<prefix##v##nelems##_t> { \
|
||||
enum : std::size_t { \
|
||||
kNumElems = nelems \
|
||||
}; \
|
||||
enum : std::size_t { kNumElems = nelems }; \
|
||||
typedef base_type BT; \
|
||||
typedef base_type BaseType; \
|
||||
typedef vec##vec_size_bits##_t T; \
|
||||
@@ -261,8 +259,7 @@ union vec8_t final {
|
||||
int8v1_t sbytes;
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(1 == sizeof(vec8_t),
|
||||
"Invalid structure packing of `vec8_t`.");
|
||||
static_assert(1 == sizeof(vec8_t), "Invalid structure packing of `vec8_t`.");
|
||||
|
||||
union vec16_t final {
|
||||
uint8v2_t bytes;
|
||||
@@ -272,10 +269,10 @@ union vec16_t final {
|
||||
int16v1_t swords;
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(2 == sizeof(vec16_t),
|
||||
"Invalid structure packing of `vec16_t`.");
|
||||
static_assert(2 == sizeof(vec16_t), "Invalid structure packing of `vec16_t`.");
|
||||
|
||||
union vec32_t final {
|
||||
|
||||
// Make this type look like an `[1 x i32]` to LLVM. This is important for
|
||||
// the cross-block alias analysis performed by remill-opt, as it enables
|
||||
// remill-opt to more easily handle false dependencies.
|
||||
@@ -290,10 +287,10 @@ union vec32_t final {
|
||||
int32v1_t sdwords;
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(4 == sizeof(vec32_t),
|
||||
"Invalid structure packing of `vec32_t`.");
|
||||
static_assert(4 == sizeof(vec32_t), "Invalid structure packing of `vec32_t`.");
|
||||
|
||||
union vec64_t final {
|
||||
|
||||
// Make this type look like an `[1 x i64]` to LLVM. This is important for
|
||||
// the cross-block alias analysis performed by remill-opt, as it enables
|
||||
// remill-opt to more easily handle false dependencies.
|
||||
@@ -313,10 +310,10 @@ union vec64_t final {
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
static_assert(8 == sizeof(vec64_t),
|
||||
"Invalid structure packing of `vec64_t`.");
|
||||
static_assert(8 == sizeof(vec64_t), "Invalid structure packing of `vec64_t`.");
|
||||
|
||||
union vec128_t final {
|
||||
|
||||
// Make this type look like an `[1 x i128]` to LLVM. This is important for
|
||||
// the cross-block alias analysis performed by remill-opt, as it enables
|
||||
// remill-opt to more easily handle false dependencies.
|
||||
@@ -374,8 +371,7 @@ union vec512_t final {
|
||||
int128v4_t sdqwords;
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(64 == sizeof(vec512_t) &&
|
||||
64 == sizeof(vec512_t().bytes) &&
|
||||
static_assert(64 == sizeof(vec512_t) && 64 == sizeof(vec512_t().bytes) &&
|
||||
64 == sizeof(vec512_t().words) &&
|
||||
64 == sizeof(vec512_t().dwords) &&
|
||||
64 == sizeof(vec512_t().qwords) &&
|
||||
@@ -580,8 +576,8 @@ struct UnsignedIntegerType;
|
||||
#define MAKE_SIGNED_INT_CHANGERS(signed_type, unsigned_type) \
|
||||
static_assert(sizeof(signed_type) == sizeof(unsigned_type), \
|
||||
"Invalid int changer type type."); \
|
||||
static_assert(is_signed<signed_type>::value != \
|
||||
is_signed<unsigned_type>::value, \
|
||||
static_assert( \
|
||||
is_signed<signed_type>::value != is_signed<unsigned_type>::value, \
|
||||
"Sign match between int type and next int type."); \
|
||||
template <> \
|
||||
struct SignedIntegerType<unsigned_type> { \
|
||||
@@ -601,8 +597,7 @@ struct UnsignedIntegerType;
|
||||
};
|
||||
|
||||
#define MAKE_INT_TYPE(cur, next) \
|
||||
static_assert(sizeof(next) == (2 * sizeof(cur)), \
|
||||
"Invalid next int type."); \
|
||||
static_assert(sizeof(next) == (2 * sizeof(cur)), "Invalid next int type."); \
|
||||
static_assert(is_signed<cur>::value == is_signed<next>::value, \
|
||||
"Sign mismatch between int type and next int type."); \
|
||||
template <> \
|
||||
@@ -667,9 +662,7 @@ struct IntegerType {
|
||||
typedef typename UnsignedIntegerType<WBT>::BT WUT;
|
||||
typedef typename SignedIntegerType<WBT>::BT WST;
|
||||
|
||||
enum : std::size_t {
|
||||
kNumBits = sizeof(BT) * 8
|
||||
};
|
||||
enum : std::size_t { kNumBits = sizeof(BT) * 8 };
|
||||
};
|
||||
|
||||
template <>
|
||||
|
||||
+96
-166
@@ -14,7 +14,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "remill/Arch/Arch.h"
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include <llvm/ADT/Triple.h>
|
||||
#include <llvm/IR/Attributes.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <map>
|
||||
@@ -22,12 +28,6 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <llvm/ADT/Triple.h>
|
||||
#include <llvm/IR/Attributes.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
|
||||
#include "remill/Arch/Arch.h"
|
||||
#include "remill/Arch/Instruction.h"
|
||||
#include "remill/Arch/Name.h"
|
||||
#include "remill/Arch/X86/XED.h"
|
||||
@@ -37,12 +37,10 @@
|
||||
namespace remill {
|
||||
namespace {
|
||||
|
||||
static const xed_state_t kXEDState32 = {
|
||||
XED_MACHINE_MODE_LONG_COMPAT_32,
|
||||
static const xed_state_t kXEDState32 = {XED_MACHINE_MODE_LONG_COMPAT_32,
|
||||
XED_ADDRESS_WIDTH_32b};
|
||||
|
||||
static const xed_state_t kXEDState64 = {
|
||||
XED_MACHINE_MODE_LONG_64,
|
||||
static const xed_state_t kXEDState64 = {XED_MACHINE_MODE_LONG_64,
|
||||
XED_ADDRESS_WIDTH_64b};
|
||||
|
||||
static bool Is64Bit(ArchName arch_name) {
|
||||
@@ -160,20 +158,16 @@ static bool UsesStopFailure(const xed_decoded_inst_t *xedd) {
|
||||
case XED_ICLASS_DIV:
|
||||
case XED_ICLASS_IDIV:
|
||||
case XED_ICLASS_XEND:
|
||||
case XED_ICLASS_XGETBV:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
case XED_ICLASS_XGETBV: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsNoOp(const xed_decoded_inst_t *xedd) {
|
||||
switch (xed_decoded_inst_get_category(xedd)) {
|
||||
case XED_CATEGORY_NOP:
|
||||
case XED_CATEGORY_WIDENOP:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
case XED_CATEGORY_WIDENOP: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,10 +176,8 @@ static bool IsError(const xed_decoded_inst_t *xedd) {
|
||||
case XED_ICLASS_HLT:
|
||||
case XED_ICLASS_UD0:
|
||||
case XED_ICLASS_UD1:
|
||||
case XED_ICLASS_UD2:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
case XED_ICLASS_UD2: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -242,8 +234,7 @@ static Instruction::Category CreateCategory(const xed_decoded_inst_t *xedd) {
|
||||
IsDirectFunctionCallFar(xedd) || IsIndirectFunctionCallFar(xedd)) {
|
||||
return Instruction::kCategoryAsyncHyperCall;
|
||||
|
||||
}
|
||||
else if (IsNoOp(xedd)) {
|
||||
} else if (IsNoOp(xedd)) {
|
||||
return Instruction::kCategoryNoOp;
|
||||
|
||||
} else {
|
||||
@@ -346,8 +337,7 @@ static std::string InstructionFunctionName(const xed_decoded_inst_t *xedd) {
|
||||
// Suffix the ISEL function name with the segment or control register names,
|
||||
// as a runtime may need to perform complex actions that are specific to
|
||||
// the register used.
|
||||
if (XED_IFORM_MOV_SEG_MEMw == iform ||
|
||||
XED_IFORM_MOV_SEG_GPR16 == iform ||
|
||||
if (XED_IFORM_MOV_SEG_MEMw == iform || XED_IFORM_MOV_SEG_GPR16 == iform ||
|
||||
XED_IFORM_MOV_CR_CR_GPR32 == iform ||
|
||||
XED_IFORM_MOV_CR_CR_GPR64 == iform) {
|
||||
ss << "_";
|
||||
@@ -358,10 +348,8 @@ static std::string InstructionFunctionName(const xed_decoded_inst_t *xedd) {
|
||||
}
|
||||
|
||||
// Decode an instruction into the XED instuction format.
|
||||
static bool DecodeXED(xed_decoded_inst_t *xedd,
|
||||
const xed_state_t *mode,
|
||||
std::string_view inst_bytes,
|
||||
uint64_t address) {
|
||||
static bool DecodeXED(xed_decoded_inst_t *xedd, const xed_state_t *mode,
|
||||
std::string_view inst_bytes, uint64_t address) {
|
||||
auto num_bytes = inst_bytes.size();
|
||||
auto bytes = reinterpret_cast<const uint8_t *>(inst_bytes.data());
|
||||
xed_decoded_inst_zero_set_mode(xedd, mode);
|
||||
@@ -374,10 +362,9 @@ static bool DecodeXED(xed_decoded_inst_t *xedd,
|
||||
ss << ' ' << std::hex << std::setw(2) << std::setfill('0')
|
||||
<< (static_cast<unsigned>(b) & 0xFFu);
|
||||
}
|
||||
LOG(ERROR)
|
||||
<< "Unable to decode instruction at " << std::hex << address
|
||||
<< " with bytes" << ss.str() << " and error: "
|
||||
<< xed_error_enum_t2str(err) << std::dec;
|
||||
LOG(ERROR) << "Unable to decode instruction at " << std::hex << address
|
||||
<< " with bytes" << ss.str()
|
||||
<< " and error: " << xed_error_enum_t2str(err) << std::dec;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -389,33 +376,15 @@ static Operand::Register RegOp(xed_reg_enum_t reg) {
|
||||
Operand::Register reg_op;
|
||||
if (XED_REG_INVALID != reg) {
|
||||
switch (reg) {
|
||||
case XED_REG_ST0:
|
||||
reg_op.name = "ST0";
|
||||
break;
|
||||
case XED_REG_ST1:
|
||||
reg_op.name = "ST1";
|
||||
break;
|
||||
case XED_REG_ST2:
|
||||
reg_op.name = "ST2";
|
||||
break;
|
||||
case XED_REG_ST3:
|
||||
reg_op.name = "ST3";
|
||||
break;
|
||||
case XED_REG_ST4:
|
||||
reg_op.name = "ST4";
|
||||
break;
|
||||
case XED_REG_ST5:
|
||||
reg_op.name = "ST5";
|
||||
break;
|
||||
case XED_REG_ST6:
|
||||
reg_op.name = "ST6";
|
||||
break;
|
||||
case XED_REG_ST7:
|
||||
reg_op.name = "ST7";
|
||||
break;
|
||||
default:
|
||||
reg_op.name = xed_reg_enum_t2str(reg);
|
||||
break;
|
||||
case XED_REG_ST0: reg_op.name = "ST0"; break;
|
||||
case XED_REG_ST1: reg_op.name = "ST1"; break;
|
||||
case XED_REG_ST2: reg_op.name = "ST2"; break;
|
||||
case XED_REG_ST3: reg_op.name = "ST3"; break;
|
||||
case XED_REG_ST4: reg_op.name = "ST4"; break;
|
||||
case XED_REG_ST5: reg_op.name = "ST5"; break;
|
||||
case XED_REG_ST6: reg_op.name = "ST6"; break;
|
||||
case XED_REG_ST7: reg_op.name = "ST7"; break;
|
||||
default: reg_op.name = xed_reg_enum_t2str(reg); break;
|
||||
}
|
||||
if (XED_REG_X87_FIRST <= reg && XED_REG_X87_LAST >= reg) {
|
||||
reg_op.size = 64;
|
||||
@@ -426,8 +395,7 @@ static Operand::Register RegOp(xed_reg_enum_t reg) {
|
||||
return reg_op;
|
||||
}
|
||||
|
||||
static Operand::Register SegBaseRegOp(xed_reg_enum_t reg,
|
||||
unsigned addr_size) {
|
||||
static Operand::Register SegBaseRegOp(xed_reg_enum_t reg, unsigned addr_size) {
|
||||
auto op = RegOp(reg);
|
||||
if (XED_REG_INVALID != reg) {
|
||||
op.name += "_BASE";
|
||||
@@ -437,10 +405,8 @@ static Operand::Register SegBaseRegOp(xed_reg_enum_t reg,
|
||||
}
|
||||
|
||||
// Decode a memory operand.
|
||||
static void DecodeMemory(Instruction &inst,
|
||||
const xed_decoded_inst_t *xedd,
|
||||
const xed_operand_t *xedo,
|
||||
int mem_index) {
|
||||
static void DecodeMemory(Instruction &inst, const xed_decoded_inst_t *xedd,
|
||||
const xed_operand_t *xedo, int mem_index) {
|
||||
|
||||
auto iform = xed_decoded_inst_get_iform_enum(xedd);
|
||||
auto iclass = xed_decoded_inst_get_iclass(xedd);
|
||||
@@ -468,8 +434,7 @@ static void DecodeMemory(Instruction &inst,
|
||||
}
|
||||
|
||||
// On AMD64, only the `FS` and `GS` segments are non-zero.
|
||||
if (Is64Bit(inst.arch_name) &&
|
||||
XED_REG_FS != segment &&
|
||||
if (Is64Bit(inst.arch_name) && XED_REG_FS != segment &&
|
||||
XED_REG_GS != segment) {
|
||||
segment = XED_REG_INVALID;
|
||||
|
||||
@@ -489,8 +454,8 @@ static void DecodeMemory(Instruction &inst,
|
||||
op.size = size;
|
||||
|
||||
op.type = Operand::kTypeAddress;
|
||||
op.addr.address_size = xed_decoded_inst_get_memop_address_width(
|
||||
xedd, mem_index);
|
||||
op.addr.address_size =
|
||||
xed_decoded_inst_get_memop_address_width(xedd, mem_index);
|
||||
|
||||
op.addr.segment_base_reg = SegBaseRegOp(segment, op.addr.address_size);
|
||||
op.addr.base_reg = RegOp(base);
|
||||
@@ -524,8 +489,7 @@ static void DecodeMemory(Instruction &inst,
|
||||
}
|
||||
|
||||
// Decode an immediate constant.
|
||||
static void DecodeImmediate(Instruction &inst,
|
||||
const xed_decoded_inst_t *xedd,
|
||||
static void DecodeImmediate(Instruction &inst, const xed_decoded_inst_t *xedd,
|
||||
xed_operand_enum_t op_name) {
|
||||
auto val = 0ULL;
|
||||
auto is_signed = false;
|
||||
@@ -538,8 +502,8 @@ static void DecodeImmediate(Instruction &inst,
|
||||
if (XED_OPERAND_PTR == op_name) {
|
||||
auto ptr_size = xed_decoded_inst_get_branch_displacement_width_bits(xedd);
|
||||
CHECK(ptr_size <= operand_size)
|
||||
<< "Pointer size is greater than effective operand size at "
|
||||
<< std::hex << inst.pc << ".";
|
||||
<< "Pointer size is greater than effective operand size at " << std::hex
|
||||
<< inst.pc << ".";
|
||||
op.size = ptr_size;
|
||||
|
||||
val = static_cast<uint64_t>(xed_decoded_inst_get_branch_displacement(xedd));
|
||||
@@ -557,14 +521,15 @@ static void DecodeImmediate(Instruction &inst,
|
||||
is_signed = true;
|
||||
|
||||
} else if (XED_OPERAND_IMM0 == op_name) {
|
||||
val = static_cast<uint64_t>(xed_decoded_inst_get_unsigned_immediate(xedd));
|
||||
val =
|
||||
static_cast<uint64_t>(xed_decoded_inst_get_unsigned_immediate(xedd));
|
||||
|
||||
} else if (XED_OPERAND_IMM1_BYTES == op_name || XED_OPERAND_IMM1 == op_name) {
|
||||
} else if (XED_OPERAND_IMM1_BYTES == op_name ||
|
||||
XED_OPERAND_IMM1 == op_name) {
|
||||
val = static_cast<uint64_t>(xed_decoded_inst_get_second_immediate(xedd));
|
||||
|
||||
} else {
|
||||
CHECK(false)
|
||||
<< "Unexpected immediate type "
|
||||
CHECK(false) << "Unexpected immediate type "
|
||||
<< xed_operand_enum_t2str(op_name) << ".";
|
||||
}
|
||||
}
|
||||
@@ -575,13 +540,11 @@ static void DecodeImmediate(Instruction &inst,
|
||||
}
|
||||
|
||||
// Decode a register operand.
|
||||
static void DecodeRegister(Instruction &inst,
|
||||
const xed_decoded_inst_t *xedd,
|
||||
static void DecodeRegister(Instruction &inst, const xed_decoded_inst_t *xedd,
|
||||
const xed_operand_t *xedo,
|
||||
xed_operand_enum_t op_name) {
|
||||
auto reg = xed_decoded_inst_get_reg(xedd, op_name);
|
||||
CHECK(XED_REG_INVALID != reg)
|
||||
<< "Cannot get name of invalid register.";
|
||||
CHECK(XED_REG_INVALID != reg) << "Cannot get name of invalid register.";
|
||||
|
||||
Operand op = {};
|
||||
op.type = Operand::kTypeRegister;
|
||||
@@ -659,8 +622,8 @@ static void DecodeConditionalBranch(Instruction &inst,
|
||||
const xed_decoded_inst_t *xedd) {
|
||||
auto pc_reg = Is64Bit(inst.arch_name) ? XED_REG_RIP : XED_REG_EIP;
|
||||
auto pc_width = xed_get_register_width_bits64(pc_reg);
|
||||
auto disp = static_cast<int64_t>(
|
||||
xed_decoded_inst_get_branch_displacement(xedd));
|
||||
auto disp =
|
||||
static_cast<int64_t>(xed_decoded_inst_get_branch_displacement(xedd));
|
||||
|
||||
// Condition variable.
|
||||
Operand cond_op = {};
|
||||
@@ -683,8 +646,8 @@ static void DecodeConditionalBranch(Instruction &inst,
|
||||
taken_op.addr.kind = Operand::Address::kControlFlowTarget;
|
||||
inst.operands.push_back(taken_op);
|
||||
|
||||
inst.branch_taken_pc = static_cast<uint64_t>(
|
||||
static_cast<int64_t>(inst.next_pc) + disp);
|
||||
inst.branch_taken_pc =
|
||||
static_cast<uint64_t>(static_cast<int64_t>(inst.next_pc) + disp);
|
||||
|
||||
DecodeFallThroughPC(inst, xedd);
|
||||
}
|
||||
@@ -694,8 +657,8 @@ static void DecodeRelativeBranch(Instruction &inst,
|
||||
const xed_decoded_inst_t *xedd) {
|
||||
auto pc_reg = Is64Bit(inst.arch_name) ? XED_REG_RIP : XED_REG_EIP;
|
||||
auto pc_width = xed_get_register_width_bits64(pc_reg);
|
||||
auto disp = static_cast<int64_t>(
|
||||
xed_decoded_inst_get_branch_displacement(xedd));
|
||||
auto disp =
|
||||
static_cast<int64_t>(xed_decoded_inst_get_branch_displacement(xedd));
|
||||
|
||||
// Taken branch.
|
||||
Operand taken_op = {};
|
||||
@@ -709,8 +672,8 @@ static void DecodeRelativeBranch(Instruction &inst,
|
||||
taken_op.addr.kind = Operand::Address::kControlFlowTarget;
|
||||
inst.operands.push_back(taken_op);
|
||||
|
||||
inst.branch_taken_pc = static_cast<uint64_t>(
|
||||
static_cast<int64_t>(inst.next_pc) + disp);
|
||||
inst.branch_taken_pc =
|
||||
static_cast<uint64_t>(static_cast<int64_t>(inst.next_pc) + disp);
|
||||
inst.branch_not_taken_pc = inst.next_pc;
|
||||
}
|
||||
|
||||
@@ -730,8 +693,8 @@ static uint16_t DecodeFpuOpcode(Instruction &inst) {
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(i >= 2)
|
||||
<< "Failed to find FPU opcode byte for instruction " << inst.Serialize();
|
||||
CHECK(i >= 2) << "Failed to find FPU opcode byte for instruction "
|
||||
<< inst.Serialize();
|
||||
|
||||
uint16_t opcode = 0;
|
||||
opcode |= static_cast<uint16_t>(bytes[0] & 3) << 8;
|
||||
@@ -762,26 +725,19 @@ static void DecodeX87LastIpDp(Instruction &inst) {
|
||||
}
|
||||
|
||||
// Decode an operand.
|
||||
static void DecodeOperand(Instruction &inst,
|
||||
const xed_decoded_inst_t *xedd,
|
||||
static void DecodeOperand(Instruction &inst, const xed_decoded_inst_t *xedd,
|
||||
const xed_operand_t *xedo) {
|
||||
switch (auto op_name = xed_operand_name(xedo)) {
|
||||
case XED_OPERAND_AGEN:
|
||||
case XED_OPERAND_MEM0:
|
||||
DecodeMemory(inst, xedd, xedo, 0);
|
||||
break;
|
||||
case XED_OPERAND_MEM0: DecodeMemory(inst, xedd, xedo, 0); break;
|
||||
|
||||
case XED_OPERAND_MEM1:
|
||||
DecodeMemory(inst, xedd, xedo, 1);
|
||||
break;
|
||||
case XED_OPERAND_MEM1: DecodeMemory(inst, xedd, xedo, 1); break;
|
||||
|
||||
case XED_OPERAND_IMM0SIGNED:
|
||||
case XED_OPERAND_IMM0:
|
||||
case XED_OPERAND_IMM1_BYTES:
|
||||
case XED_OPERAND_IMM1:
|
||||
case XED_OPERAND_PTR:
|
||||
DecodeImmediate(inst, xedd, op_name);
|
||||
break;
|
||||
case XED_OPERAND_PTR: DecodeImmediate(inst, xedd, op_name); break;
|
||||
|
||||
case XED_OPERAND_REG:
|
||||
case XED_OPERAND_REG0:
|
||||
@@ -792,9 +748,7 @@ static void DecodeOperand(Instruction &inst,
|
||||
case XED_OPERAND_REG5:
|
||||
case XED_OPERAND_REG6:
|
||||
case XED_OPERAND_REG7:
|
||||
case XED_OPERAND_REG8:
|
||||
DecodeRegister(inst, xedd, xedo, op_name);
|
||||
break;
|
||||
case XED_OPERAND_REG8: DecodeRegister(inst, xedd, xedo, op_name); break;
|
||||
|
||||
case XED_OPERAND_RELBR:
|
||||
if (Instruction::kCategoryConditionalBranch == inst.category) {
|
||||
@@ -805,8 +759,7 @@ static void DecodeOperand(Instruction &inst,
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG(FATAL)
|
||||
<< "Unexpected operand type "
|
||||
LOG(FATAL) << "Unexpected operand type "
|
||||
<< xed_operand_enum_t2str(op_name) << ".";
|
||||
return;
|
||||
}
|
||||
@@ -825,15 +778,13 @@ class X86Arch final : public Arch {
|
||||
const char *ProgramCounterRegisterName(void) const final;
|
||||
|
||||
// Decode an instuction.
|
||||
bool DecodeInstruction(
|
||||
uint64_t address, std::string_view inst_bytes,
|
||||
bool DecodeInstruction(uint64_t address, std::string_view inst_bytes,
|
||||
Instruction &inst) const final;
|
||||
|
||||
// Fully decode any control-flow transfer instructions, but only partially
|
||||
// decode other instructions. To complete the decoding, call
|
||||
// `Instruction::FinalizeDecode`.
|
||||
bool LazyDecodeInstruction(
|
||||
uint64_t address, std::string_view inst_bytes,
|
||||
bool LazyDecodeInstruction(uint64_t address, std::string_view inst_bytes,
|
||||
Instruction &inst) const final;
|
||||
|
||||
// Maximum number of bytes in an instruction.
|
||||
@@ -846,17 +797,16 @@ class X86Arch final : public Arch {
|
||||
llvm::CallingConv::ID DefaultCallingConv(void) const final;
|
||||
|
||||
private:
|
||||
|
||||
// Decode an instuction.
|
||||
bool DecodeInstruction(
|
||||
uint64_t address, std::string_view inst_bytes,
|
||||
bool DecodeInstruction(uint64_t address, std::string_view inst_bytes,
|
||||
Instruction &inst, bool is_lazy) const;
|
||||
|
||||
X86Arch(void) = delete;
|
||||
};
|
||||
|
||||
|
||||
X86Arch::X86Arch(llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_)
|
||||
X86Arch::X86Arch(llvm::LLVMContext *context_, OSName os_name_,
|
||||
ArchName arch_name_)
|
||||
: Arch(context_, os_name_, arch_name_) {
|
||||
|
||||
static bool xed_is_initialized = false;
|
||||
@@ -882,18 +832,15 @@ llvm::CallingConv::ID X86Arch::DefaultCallingConv(void) const {
|
||||
case kOSmacOS:
|
||||
case kOSLinux:
|
||||
case kOSWindows:
|
||||
case kOSSolaris:
|
||||
return llvm::CallingConv::C; // cdecl.
|
||||
case kOSSolaris: return llvm::CallingConv::C; // cdecl.
|
||||
}
|
||||
} else {
|
||||
switch (os_name) {
|
||||
case kOSInvalid:
|
||||
case kOSmacOS:
|
||||
case kOSLinux:
|
||||
case kOSSolaris:
|
||||
return llvm::CallingConv::X86_64_SysV;
|
||||
case kOSWindows:
|
||||
return llvm::CallingConv::Win64;
|
||||
case kOSSolaris: return llvm::CallingConv::X86_64_SysV;
|
||||
case kOSWindows: return llvm::CallingConv::Win64;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -904,17 +851,12 @@ llvm::Triple X86Arch::Triple(void) const {
|
||||
switch (arch_name) {
|
||||
case kArchAMD64:
|
||||
case kArchAMD64_AVX:
|
||||
case kArchAMD64_AVX512:
|
||||
triple.setArch(llvm::Triple::x86_64);
|
||||
break;
|
||||
case kArchAMD64_AVX512: triple.setArch(llvm::Triple::x86_64); break;
|
||||
case kArchX86:
|
||||
case kArchX86_AVX:
|
||||
case kArchX86_AVX512:
|
||||
triple.setArch(llvm::Triple::x86);
|
||||
break;
|
||||
case kArchX86_AVX512: triple.setArch(llvm::Triple::x86); break;
|
||||
default:
|
||||
LOG(FATAL)
|
||||
<< "Cannot get triple for non-x86 architecture "
|
||||
LOG(FATAL) << "Cannot get triple for non-x86 architecture "
|
||||
<< GetArchName(arch_name);
|
||||
}
|
||||
|
||||
@@ -943,8 +885,7 @@ llvm::DataLayout X86Arch::DataLayout(void) const {
|
||||
dl = "e-m:e-p:32:32-f64:32:64-f80:32-n8:16:32-S128";
|
||||
break;
|
||||
default:
|
||||
LOG(FATAL)
|
||||
<< "Cannot get data layout non-x86 architecture "
|
||||
LOG(FATAL) << "Cannot get data layout non-x86 architecture "
|
||||
<< GetArchName(arch_name);
|
||||
break;
|
||||
}
|
||||
@@ -963,8 +904,7 @@ llvm::DataLayout X86Arch::DataLayout(void) const {
|
||||
dl = "e-m:o-p:32:32-f64:32:64-f80:128-n8:16:32-S128";
|
||||
break;
|
||||
default:
|
||||
LOG(FATAL)
|
||||
<< "Cannot get data layout for non-x86 architecture "
|
||||
LOG(FATAL) << "Cannot get data layout for non-x86 architecture "
|
||||
<< GetArchName(arch_name);
|
||||
}
|
||||
break;
|
||||
@@ -982,8 +922,7 @@ llvm::DataLayout X86Arch::DataLayout(void) const {
|
||||
dl = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32";
|
||||
break;
|
||||
default:
|
||||
LOG(FATAL)
|
||||
<< "Cannot get data layout for non-x86 architecture "
|
||||
LOG(FATAL) << "Cannot get data layout for non-x86 architecture "
|
||||
<< GetArchName(arch_name);
|
||||
}
|
||||
break;
|
||||
@@ -993,9 +932,7 @@ llvm::DataLayout X86Arch::DataLayout(void) const {
|
||||
}
|
||||
|
||||
// Decode an instuction.
|
||||
bool X86Arch::DecodeInstruction(
|
||||
uint64_t address,
|
||||
std::string_view inst_bytes,
|
||||
bool X86Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes,
|
||||
Instruction &inst, bool is_lazy) const {
|
||||
|
||||
inst.pc = address;
|
||||
@@ -1007,8 +944,7 @@ bool X86Arch::DecodeInstruction(
|
||||
auto mode = 32 == address_size ? &kXEDState32 : &kXEDState64;
|
||||
|
||||
if (!DecodeXED(xedd, mode, inst_bytes, address)) {
|
||||
LOG(ERROR)
|
||||
<< "DecodeXED() could not decode the following opcodes: "
|
||||
LOG(ERROR) << "DecodeXED() could not decode the following opcodes: "
|
||||
<< inst.Serialize();
|
||||
return false;
|
||||
}
|
||||
@@ -1079,6 +1015,7 @@ bool X86Arch::DecodeInstruction(
|
||||
}
|
||||
|
||||
if (UsesStopFailure(xedd)) {
|
||||
|
||||
// These instructions might fault and uses the StopFailure to recover.
|
||||
// The new operand `next_pc` is added and the REG_PC is set to next_pc
|
||||
// before calling the StopFailure
|
||||
@@ -1104,9 +1041,7 @@ bool X86Arch::DecodeInstruction(
|
||||
case XED_IFORM_FINCSTP:
|
||||
case XED_IFORM_FDECSTP:
|
||||
case XED_IFORM_FFREE_X87:
|
||||
case XED_IFORM_FFREEP_X87:
|
||||
set_ip_dp = true;
|
||||
break;
|
||||
case XED_IFORM_FFREEP_X87: set_ip_dp = true; break;
|
||||
default:
|
||||
set_ip_dp = !get_attr(xedd, XED_ATTRIBUTE_X87_CONTROL) &&
|
||||
!get_attr(xedd, XED_ATTRIBUTE_X87_MMX_STATE_CW) &&
|
||||
@@ -1123,8 +1058,7 @@ bool X86Arch::DecodeInstruction(
|
||||
|
||||
if (xed_decoded_inst_is_xacquire(xedd) ||
|
||||
xed_decoded_inst_is_xrelease(xedd)) {
|
||||
LOG(ERROR)
|
||||
<< "Ignoring XACQUIRE/XRELEASE prefix at " << std::hex
|
||||
LOG(ERROR) << "Ignoring XACQUIRE/XRELEASE prefix at " << std::hex
|
||||
<< inst.pc << std::dec;
|
||||
}
|
||||
}
|
||||
@@ -1134,8 +1068,7 @@ bool X86Arch::DecodeInstruction(
|
||||
switch (xed_decoded_inst_get_isa_set(xedd)) {
|
||||
case XED_ISA_SET_INVALID:
|
||||
case XED_ISA_SET_LAST:
|
||||
LOG(ERROR)
|
||||
<< "Instruction decode of " << xed_iform_enum_t2str(iform)
|
||||
LOG(ERROR) << "Instruction decode of " << xed_iform_enum_t2str(iform)
|
||||
<< " failed because XED_ISA_SET_LAST.";
|
||||
return false;
|
||||
|
||||
@@ -1144,12 +1077,12 @@ bool X86Arch::DecodeInstruction(
|
||||
case XED_ISA_SET_AVX2GATHER:
|
||||
case XED_ISA_SET_AVXAES:
|
||||
case XED_ISA_SET_AVX_GFNI: {
|
||||
auto supp = kArchAMD64 != inst.arch_name &&
|
||||
kArchX86 != inst.arch_name;
|
||||
LOG_IF(ERROR, !supp)
|
||||
<< "Instruction decode of " << xed_iform_enum_t2str(iform)
|
||||
auto supp = kArchAMD64 != inst.arch_name && kArchX86 != inst.arch_name;
|
||||
LOG_IF(ERROR, !supp) << "Instruction decode of "
|
||||
<< xed_iform_enum_t2str(iform)
|
||||
<< " failed because the current arch is specified "
|
||||
<< "as " << GetArchName(inst.arch_name) << " but what is needed is "
|
||||
<< "as " << GetArchName(inst.arch_name)
|
||||
<< " but what is needed is "
|
||||
<< "the _avx or _avx512 variant.";
|
||||
return supp;
|
||||
}
|
||||
@@ -1210,10 +1143,10 @@ bool X86Arch::DecodeInstruction(
|
||||
const auto supp = kArchAMD64_AVX512 == inst.arch_name ||
|
||||
kArchX86_AVX512 == inst.arch_name;
|
||||
if (!supp) {
|
||||
LOG(ERROR)
|
||||
<< "Instruction decode of " << xed_iform_enum_t2str(iform)
|
||||
LOG(ERROR) << "Instruction decode of " << xed_iform_enum_t2str(iform)
|
||||
<< " failed because the current arch is specified "
|
||||
<< "as " << GetArchName(inst.arch_name) << " but what is needed is "
|
||||
<< "as " << GetArchName(inst.arch_name)
|
||||
<< " but what is needed is "
|
||||
<< "the _avx512 variant.";
|
||||
inst.Reset();
|
||||
inst.category = Instruction::kCategoryInvalid;
|
||||
@@ -1221,8 +1154,7 @@ bool X86Arch::DecodeInstruction(
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -1246,9 +1178,7 @@ const char *X86Arch::ProgramCounterRegisterName(void) const {
|
||||
}
|
||||
}
|
||||
|
||||
bool X86Arch::DecodeInstruction(
|
||||
uint64_t address,
|
||||
std::string_view inst_bytes,
|
||||
bool X86Arch::DecodeInstruction(uint64_t address, std::string_view inst_bytes,
|
||||
Instruction &inst) const {
|
||||
inst.arch_for_decode = nullptr;
|
||||
return DecodeInstruction(address, inst_bytes, inst, false);
|
||||
@@ -1256,8 +1186,8 @@ bool X86Arch::DecodeInstruction(
|
||||
|
||||
// Fully decode any control-flow transfer instructions, but only partially
|
||||
// decode other instructions.
|
||||
bool X86Arch::LazyDecodeInstruction(
|
||||
uint64_t address, std::string_view inst_bytes,
|
||||
bool X86Arch::LazyDecodeInstruction(uint64_t address,
|
||||
std::string_view inst_bytes,
|
||||
Instruction &inst) const {
|
||||
inst.arch_for_decode = nullptr;
|
||||
if (DecodeInstruction(address, inst_bytes, inst, true)) {
|
||||
@@ -1273,8 +1203,8 @@ bool X86Arch::LazyDecodeInstruction(
|
||||
} // namespace
|
||||
|
||||
// TODO(pag): We pretend that these are singletons, but they aren't really!
|
||||
Arch::ArchPtr Arch::GetX86(
|
||||
llvm::LLVMContext *context_, OSName os_name_, ArchName arch_name_) {
|
||||
Arch::ArchPtr Arch::GetX86(llvm::LLVMContext *context_, OSName os_name_,
|
||||
ArchName arch_name_) {
|
||||
return std::make_unique<X86Arch>(context_, os_name_, arch_name_);
|
||||
}
|
||||
|
||||
|
||||
@@ -48,8 +48,8 @@ extern CR8Reg gCR8;
|
||||
// each basic block in the code being lifted.
|
||||
//
|
||||
// Note: `curr_pc` is first to make sure it's not optimized away.
|
||||
[[gnu::used]]
|
||||
Memory *__remill_basic_block(State &state, addr_t curr_pc, Memory *memory) {
|
||||
[[gnu::used]] Memory *__remill_basic_block(State &state, addr_t curr_pc,
|
||||
Memory *memory) {
|
||||
|
||||
bool branch_taken = false;
|
||||
addr_t zero1 = 0;
|
||||
|
||||
@@ -18,13 +18,14 @@
|
||||
#include <bitset>
|
||||
#include <cmath>
|
||||
|
||||
// clang-format off
|
||||
#include "remill/Arch/Float.h"
|
||||
#include "remill/Arch/Runtime/Intrinsics.h"
|
||||
#include "remill/Arch/Runtime/Operators.h"
|
||||
|
||||
#include "remill/Arch/X86/Runtime/State.h"
|
||||
#include "remill/Arch/X86/Runtime/Types.h"
|
||||
#include "remill/Arch/X86/Runtime/Operators.h"
|
||||
// clang-format on
|
||||
|
||||
#define REG_IP state.gpr.rip.word
|
||||
#define REG_EIP state.gpr.rip.dword
|
||||
@@ -131,10 +132,12 @@
|
||||
#define INTERRUPT_VECTOR state.hyper_call_vector
|
||||
|
||||
namespace {
|
||||
|
||||
// Takes the place of an unsupported instruction.
|
||||
DEF_SEM(HandleUnsupported) {
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, IF_64BIT_ELSE(SyncHyperCall::kAMD64EmulateInstruction,
|
||||
state, memory,
|
||||
IF_64BIT_ELSE(SyncHyperCall::kAMD64EmulateInstruction,
|
||||
SyncHyperCall::kX86EmulateInstruction));
|
||||
}
|
||||
|
||||
@@ -162,7 +165,9 @@ DEF_HELPER(PopFromStack) -> T {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// clang-format off
|
||||
#include "remill/Arch/X86/Semantics/FLAGS.cpp"
|
||||
|
||||
#include "remill/Arch/X86/Semantics/AVX.cpp"
|
||||
#include "remill/Arch/X86/Semantics/BINARY.cpp"
|
||||
#include "remill/Arch/X86/Semantics/BITBYTE.cpp"
|
||||
@@ -172,9 +177,9 @@ DEF_HELPER(PopFromStack) -> T {
|
||||
#include "remill/Arch/X86/Semantics/CONVERT.cpp"
|
||||
#include "remill/Arch/X86/Semantics/DATAXFER.cpp"
|
||||
#include "remill/Arch/X86/Semantics/DECIMAL.cpp"
|
||||
#include "remill/Arch/X86/Semantics/INTERRUPT.cpp"
|
||||
#include "remill/Arch/X86/Semantics/FLAGOP.cpp"
|
||||
#include "remill/Arch/X86/Semantics/FMA.cpp"
|
||||
#include "remill/Arch/X86/Semantics/INTERRUPT.cpp"
|
||||
#include "remill/Arch/X86/Semantics/IO.cpp"
|
||||
#include "remill/Arch/X86/Semantics/LOGICAL.cpp"
|
||||
#include "remill/Arch/X86/Semantics/MISC.cpp"
|
||||
@@ -195,3 +200,4 @@ DEF_HELPER(PopFromStack) -> T {
|
||||
#include "remill/Arch/X86/Semantics/X87.cpp"
|
||||
#include "remill/Arch/X86/Semantics/XOP.cpp"
|
||||
#include "remill/Arch/X86/Semantics/XSAVE.cpp"
|
||||
// clang-format on
|
||||
|
||||
@@ -19,25 +19,23 @@
|
||||
namespace {
|
||||
|
||||
// Read a register directly. Sometimes this is needed for suppressed operands.
|
||||
ALWAYS_INLINE static
|
||||
IF_64BIT_ELSE(uint64_t, uint32_t) _Read(Memory *, Reg reg) {
|
||||
ALWAYS_INLINE static IF_64BIT_ELSE(uint64_t, uint32_t)
|
||||
_Read(Memory *, Reg reg) {
|
||||
return reg.IF_64BIT_ELSE(qword, dword);
|
||||
}
|
||||
|
||||
// Write directly to a register. This is sometimes needed for suppressed
|
||||
// register operands.
|
||||
ALWAYS_INLINE static
|
||||
void _Write(Memory *, Reg ®, IF_64BIT_ELSE(uint64_t, uint32_t) val) {
|
||||
ALWAYS_INLINE static void _Write(Memory *, Reg ®,
|
||||
IF_64BIT_ELSE(uint64_t, uint32_t) val) {
|
||||
reg.IF_64BIT_ELSE(qword, dword) = val;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE static
|
||||
bcd80_t _ReadBCD80(Memory *memory, Mn<bcd80_t> op) {
|
||||
ALWAYS_INLINE static bcd80_t _ReadBCD80(Memory *memory, Mn<bcd80_t> op) {
|
||||
bcd80_t bcd = {};
|
||||
const auto num_digit_pairs = sizeof(bcd.digit_pairs);
|
||||
|
||||
_Pragma("unroll")
|
||||
for (addr_t i = 0; i < num_digit_pairs; i++) {
|
||||
_Pragma("unroll") for (addr_t i = 0; i < num_digit_pairs; i++) {
|
||||
bcd.digit_pairs[i].u8 = __remill_read_memory_8(memory, op.addr + i);
|
||||
}
|
||||
auto msb = __remill_read_memory_8(memory, op.addr + num_digit_pairs);
|
||||
@@ -48,13 +46,13 @@ bcd80_t _ReadBCD80(Memory *memory, Mn<bcd80_t> op) {
|
||||
|
||||
#define ReadBCD80(op) _ReadBCD80(memory, op)
|
||||
|
||||
ALWAYS_INLINE static
|
||||
Memory *_WriteBCD80(Memory *memory, MBCD80W dst, bcd80_t src) {
|
||||
ALWAYS_INLINE static Memory *_WriteBCD80(Memory *memory, MBCD80W dst,
|
||||
bcd80_t src) {
|
||||
const auto num_digit_pairs = sizeof(src.digit_pairs);
|
||||
|
||||
_Pragma("unroll")
|
||||
for (addr_t i = 0; i < num_digit_pairs; i++) {
|
||||
memory = __remill_write_memory_8(memory, dst.addr + i, src.digit_pairs[i].u8);
|
||||
_Pragma("unroll") for (addr_t i = 0; i < num_digit_pairs; i++) {
|
||||
memory =
|
||||
__remill_write_memory_8(memory, dst.addr + i, src.digit_pairs[i].u8);
|
||||
}
|
||||
|
||||
uint8_t msb = static_cast<uint8_t>(src.is_negative << 7);
|
||||
@@ -65,14 +63,13 @@ Memory *_WriteBCD80(Memory *memory, MBCD80W dst, bcd80_t src) {
|
||||
|
||||
#define WriteBCD80(op, val) _WriteBCD80(memory, op, val)
|
||||
|
||||
ALWAYS_INLINE static
|
||||
Memory *_WriteBCD80Indefinite(Memory *memory, MBCD80W dst) {
|
||||
ALWAYS_INLINE static Memory *_WriteBCD80Indefinite(Memory *memory,
|
||||
MBCD80W dst) {
|
||||
const uint8_t indefinite[sizeof(bcd80_t)] = {
|
||||
0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0, 0xff, 0xff,
|
||||
};
|
||||
|
||||
_Pragma("unroll")
|
||||
for (addr_t i = 0; i < sizeof(indefinite); i++) {
|
||||
_Pragma("unroll") for (addr_t i = 0; i < sizeof(indefinite); i++) {
|
||||
memory = __remill_write_memory_8(memory, dst.addr + i, indefinite[i]);
|
||||
}
|
||||
|
||||
|
||||
@@ -134,10 +134,7 @@ enum FPURoundingControl : uint16_t {
|
||||
kFPURoundToZero
|
||||
};
|
||||
|
||||
enum FPUInfinityControl : uint16_t {
|
||||
kInfinityProjective,
|
||||
kInfinityAffine
|
||||
};
|
||||
enum FPUInfinityControl : uint16_t { kInfinityProjective, kInfinityAffine };
|
||||
|
||||
union FPUControlWord final {
|
||||
uint16_t flat;
|
||||
@@ -218,10 +215,7 @@ enum FPUTag : uint16_t {
|
||||
kFPUTagEmpty
|
||||
};
|
||||
|
||||
enum FPUAbridgedTag : uint8_t {
|
||||
kFPUAbridgedTagEmpty,
|
||||
kFPUAbridgedTagValid
|
||||
};
|
||||
enum FPUAbridgedTag : uint8_t { kFPUAbridgedTagEmpty, kFPUAbridgedTagValid };
|
||||
|
||||
// Note: Stored in top-of-stack order.
|
||||
union FPUTagWord final {
|
||||
@@ -400,6 +394,7 @@ union alignas(8) Flags final {
|
||||
static_assert(8 == sizeof(Flags), "Invalid structure packing of `Flags`.");
|
||||
|
||||
struct alignas(8) ArithFlags final {
|
||||
|
||||
// Prevents LLVM from casting and `ArithFlags` into an `i8` to access `cf`.
|
||||
volatile uint8_t _0;
|
||||
uint8_t cf; // Prevents load/store coalescing.
|
||||
@@ -437,7 +432,8 @@ union XCR0 {
|
||||
uint64_t bndreg : 1; // Part of MPX.
|
||||
uint64_t bndcsr : 1; // Part of MPX.
|
||||
uint64_t opmask : 1; // Registers k0 through k7, AVX512-only.
|
||||
uint64_t zmm_hi256:1; // High 256 bits of ZMM0 through ZMM15, AVX512-only.
|
||||
uint64_t
|
||||
zmm_hi256 : 1; // High 256 bits of ZMM0 through ZMM15, AVX512-only.
|
||||
uint64_t hi16_zmm : 1; // ZMM16 through ZMM31, AVX512-only.
|
||||
uint64_t pkru : 1; // Protected key stuff.
|
||||
uint64_t _reserved0 : 53;
|
||||
@@ -474,7 +470,8 @@ struct alignas(8) SegmentCaches final {
|
||||
SegmentShadow gs;
|
||||
} __attribute__((packed));
|
||||
|
||||
static_assert(96 == sizeof(SegmentCaches), "Invalid packing of `struct SegmentCaches`.");
|
||||
static_assert(96 == sizeof(SegmentCaches),
|
||||
"Invalid packing of `struct SegmentCaches`.");
|
||||
|
||||
enum DescriptorPrivilegeLevel : uint64_t {
|
||||
kDPLRingZero = 0,
|
||||
@@ -501,10 +498,7 @@ enum SegmentDefaultOperandSize : uint64_t {
|
||||
kSegmentDefaultOperandSize32
|
||||
};
|
||||
|
||||
enum SegmentPresentStatus : uint64_t {
|
||||
kSegmentNotPresent,
|
||||
kSegmentPresent
|
||||
};
|
||||
enum SegmentPresentStatus : uint64_t { kSegmentNotPresent, kSegmentPresent };
|
||||
|
||||
enum SystemDescriptorType : uint64_t {
|
||||
kSystemTypeIllegal0,
|
||||
@@ -530,10 +524,7 @@ enum CodeSegmentMode : uint64_t {
|
||||
kSegment64BitMode
|
||||
};
|
||||
|
||||
enum SegmentSystemBit : uint64_t {
|
||||
kSegmentBitSystem,
|
||||
kSegmentBitUser
|
||||
};
|
||||
enum SegmentSystemBit : uint64_t { kSegmentBitSystem, kSegmentBitUser };
|
||||
|
||||
struct GenericDescriptor {
|
||||
uint64_t unused : 44;
|
||||
@@ -675,6 +666,7 @@ static_assert(96 == sizeof(AddressSpace),
|
||||
// not be referenced by named variables in the `__remill_basic_block`
|
||||
// function.
|
||||
struct alignas(8) GPR final {
|
||||
|
||||
// Prevents LLVM from casting a `GPR` into an `i64` to access `rax`.
|
||||
volatile uint64_t _0;
|
||||
Reg rax;
|
||||
@@ -735,11 +727,10 @@ struct alignas(8) MMX final {
|
||||
|
||||
static_assert(128 == sizeof(MMX), "Invalid structure packing of `MMX`.");
|
||||
|
||||
enum : size_t {
|
||||
kNumVecRegisters = 32
|
||||
};
|
||||
enum : size_t { kNumVecRegisters = 32 };
|
||||
|
||||
struct alignas(16) State final : public ArchState {
|
||||
|
||||
// ArchState occupies 16 bytes.
|
||||
|
||||
// AVX512 has 32 vector registers, so we always include them all here for
|
||||
|
||||
@@ -70,8 +70,7 @@ typedef Vn<vec512_t> VV512; // AVX512 ZMM register.
|
||||
// represent that. We distinguish SSE and AVX semantics by using things like
|
||||
// `V128W` for writing to an XMM register, but `VV128W` for writing to an
|
||||
// extended AVX(512) register like YMM or ZMM.
|
||||
typedef IF_AVX512_ELSE(vec512_t, IF_AVX_ELSE(vec256_t, vec128_t))
|
||||
WriteVecType;
|
||||
typedef IF_AVX512_ELSE(vec512_t, IF_AVX_ELSE(vec256_t, vec128_t)) WriteVecType;
|
||||
typedef RVnW<IF_64BIT_ELSE(vec64_t, vec32_t)> V32W; // GPR with vector.
|
||||
typedef RVnW<vec64_t> V64W; // MMX technology register, or GPR with vector.
|
||||
typedef VnW<vec128_t> V128W; // Legacy (SSE) XMM register.
|
||||
|
||||
@@ -19,8 +19,7 @@
|
||||
namespace {
|
||||
|
||||
DEF_SEM(DoVZEROUPPER) {
|
||||
_Pragma("unroll")
|
||||
for (unsigned i = 0; i < IF_64BIT_ELSE(16, 8); ++i) {
|
||||
_Pragma("unroll") for (unsigned i = 0; i < IF_64BIT_ELSE(16, 8); ++i) {
|
||||
auto &vec = state.vec[i];
|
||||
vec.ymm.dqwords.elems[1] = 0;
|
||||
IF_AVX512(vec.zmm.dqwords.elems[2] = 0;)
|
||||
|
||||
@@ -244,16 +244,14 @@ DEF_ISEL_Rn_In(CMP_OrAX_IMMz, CMP);
|
||||
namespace {
|
||||
|
||||
template <typename T, typename U, typename V>
|
||||
ALWAYS_INLINE static
|
||||
void WriteFlagsMul(State &state, T lhs, T rhs, U res, V res_trunc) {
|
||||
ALWAYS_INLINE static void WriteFlagsMul(State &state, T lhs, T rhs, U res,
|
||||
V res_trunc) {
|
||||
const auto new_of = Overflow<tag_mul>::Flag(lhs, rhs, res);
|
||||
FLAG_CF = new_of;
|
||||
FLAG_PF = ParityFlag(res); // Technically undefined.
|
||||
FLAG_AF = BUndefined();
|
||||
FLAG_ZF = BUndefined();
|
||||
FLAG_SF = std::is_signed<T>::value ?
|
||||
SignFlag(res_trunc) :
|
||||
BUndefined();
|
||||
FLAG_SF = std::is_signed<T>::value ? SignFlag(res_trunc) : BUndefined();
|
||||
FLAG_OF = new_of;
|
||||
}
|
||||
|
||||
@@ -307,8 +305,7 @@ DEF_SEM(MULX, D dst1, D dst2, const S2 src2) {
|
||||
return memory; \
|
||||
}
|
||||
|
||||
MAKE_MULxax(al, REG_AL, REG_AL, REG_AH)
|
||||
MAKE_MULxax(ax, REG_AX, REG_AX, REG_DX)
|
||||
MAKE_MULxax(al, REG_AL, REG_AL, REG_AH) MAKE_MULxax(ax, REG_AX, REG_AX, REG_DX)
|
||||
MAKE_MULxax(eax, REG_EAX, REG_XAX, REG_XDX)
|
||||
IF_64BIT(MAKE_MULxax(rax, REG_RAX, REG_RAX, REG_RDX))
|
||||
|
||||
@@ -502,7 +499,8 @@ IF_64BIT(MAKE_DIVxax(rdxrax, REG_RAX, REG_RDX, REG_RAX, REG_RDX))
|
||||
MAKE_IDIVxax(ax, REG_AL, REG_AH, REG_AL, REG_AH)
|
||||
MAKE_IDIVxax(dxax, REG_AX, REG_DX, REG_AX, REG_DX)
|
||||
MAKE_IDIVxax(edxeax, REG_EAX, REG_EDX, REG_XAX, REG_XDX)
|
||||
IF_64BIT(MAKE_IDIVxax(rdxrax, REG_RAX, REG_RDX, REG_RAX, REG_RDX))
|
||||
IF_64BIT(MAKE_IDIVxax(rdxrax, REG_RAX, REG_RDX,
|
||||
REG_RAX, REG_RDX))
|
||||
|
||||
#undef MAKE_IDIVxax
|
||||
|
||||
|
||||
@@ -259,6 +259,7 @@ DEF_SEM(BSWAP_16, R16W dst, R16 src) {
|
||||
}
|
||||
|
||||
DEF_SEM(BSWAP_32, R32W dst, R32 src) {
|
||||
|
||||
// auto val = Read(src);
|
||||
// auto d = UAnd(val, 0xff);
|
||||
// auto c = UAnd(UShr(val, 8), 0xff);
|
||||
|
||||
@@ -139,4 +139,4 @@ DEF_SEM(IRETQ, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
|
||||
DEF_ISEL(IRETQ_64) = IRETQ;
|
||||
#endif
|
||||
}
|
||||
} // namespace
|
||||
|
||||
@@ -19,10 +19,8 @@
|
||||
namespace {
|
||||
template <typename D, typename S1>
|
||||
DEF_SEM(CMOVNLE, D dst, S1 src1) {
|
||||
WriteZExt(dst, Select(
|
||||
BAnd(BNot(FLAG_ZF), BXnor(FLAG_SF, FLAG_OF)),
|
||||
Read(src1),
|
||||
TruncTo<S1>(Read(dst))));
|
||||
WriteZExt(dst, Select(BAnd(BNot(FLAG_ZF), BXnor(FLAG_SF, FLAG_OF)),
|
||||
Read(src1), TruncTo<S1>(Read(dst))));
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -34,10 +32,8 @@ DEF_SEM(CMOVNS, D dst, S1 src1) {
|
||||
|
||||
template <typename D, typename S1>
|
||||
DEF_SEM(CMOVL, D dst, S1 src1) {
|
||||
WriteZExt(dst, Select(
|
||||
BXor(FLAG_SF, FLAG_OF),
|
||||
Read(src1),
|
||||
TruncTo<S1>(Read(dst))));
|
||||
WriteZExt(dst,
|
||||
Select(BXor(FLAG_SF, FLAG_OF), Read(src1), TruncTo<S1>(Read(dst))));
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -68,28 +64,22 @@ DEF_SEM(CMOVNO, D dst, S1 src1) {
|
||||
|
||||
template <typename D, typename S1>
|
||||
DEF_SEM(CMOVNL, D dst, S1 src1) {
|
||||
WriteZExt(dst, Select(
|
||||
BXnor(FLAG_SF, FLAG_OF),
|
||||
Read(src1),
|
||||
TruncTo<S1>(Read(dst))));
|
||||
WriteZExt(
|
||||
dst, Select(BXnor(FLAG_SF, FLAG_OF), Read(src1), TruncTo<S1>(Read(dst))));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename D, typename S1>
|
||||
DEF_SEM(CMOVNBE, D dst, S1 src1) {
|
||||
WriteZExt(dst, Select(
|
||||
BNot(BOr(FLAG_CF, FLAG_ZF)),
|
||||
Read(src1),
|
||||
WriteZExt(dst, Select(BNot(BOr(FLAG_CF, FLAG_ZF)), Read(src1),
|
||||
TruncTo<S1>(Read(dst))));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename D, typename S1>
|
||||
DEF_SEM(CMOVBE, D dst, S1 src1) {
|
||||
WriteZExt(dst, Select(
|
||||
BOr(FLAG_CF, FLAG_ZF),
|
||||
Read(src1),
|
||||
TruncTo<S1>(Read(dst))));
|
||||
WriteZExt(dst,
|
||||
Select(BOr(FLAG_CF, FLAG_ZF), Read(src1), TruncTo<S1>(Read(dst))));
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -125,9 +115,7 @@ DEF_SEM(CMOVB, D dst, S1 src1) {
|
||||
|
||||
template <typename D, typename S1>
|
||||
DEF_SEM(CMOVLE, D dst, S1 src1) {
|
||||
WriteZExt(dst, Select(
|
||||
BOr(FLAG_ZF, BXor(FLAG_SF, FLAG_OF)),
|
||||
Read(src1),
|
||||
WriteZExt(dst, Select(BOr(FLAG_ZF, BXor(FLAG_SF, FLAG_OF)), Read(src1),
|
||||
TruncTo<S1>(Read(dst))));
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
|
||||
namespace {
|
||||
|
||||
DEF_SEM(JNLE, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JNLE, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = BAnd(BNot(FLAG_ZF), BXnor(FLAG_SF, FLAG_OF));
|
||||
@@ -25,7 +26,8 @@ DEF_SEM(JNLE, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JNS, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JNS, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = BNot(FLAG_SF);
|
||||
@@ -34,7 +36,8 @@ DEF_SEM(JNS, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst)
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JL, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JL, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = BXor(FLAG_SF, FLAG_OF);
|
||||
@@ -43,7 +46,8 @@ DEF_SEM(JL, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst)
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JNP, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JNP, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = BNot(FLAG_PF);
|
||||
@@ -52,7 +56,8 @@ DEF_SEM(JNP, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst)
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JNZ, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JNZ, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = BNot(FLAG_ZF);
|
||||
@@ -61,7 +66,8 @@ DEF_SEM(JNZ, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst)
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JNB, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JNB, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = BNot(FLAG_CF);
|
||||
@@ -70,7 +76,8 @@ DEF_SEM(JNB, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst)
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JNO, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JNO, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = BNot(FLAG_OF);
|
||||
@@ -79,7 +86,8 @@ DEF_SEM(JNO, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst)
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JNL, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JNL, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = BXnor(FLAG_SF, FLAG_OF);
|
||||
@@ -88,7 +96,8 @@ DEF_SEM(JNL, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst)
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JNBE, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JNBE, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = BNot(BOr(FLAG_CF, FLAG_ZF));
|
||||
@@ -97,7 +106,8 @@ DEF_SEM(JNBE, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JBE, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JBE, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = BOr(FLAG_CF, FLAG_ZF);
|
||||
@@ -106,7 +116,8 @@ DEF_SEM(JBE, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst)
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JZ, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JZ, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = FLAG_ZF;
|
||||
@@ -115,7 +126,8 @@ DEF_SEM(JZ, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst)
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JP, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JP, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = FLAG_PF;
|
||||
@@ -124,7 +136,8 @@ DEF_SEM(JP, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst)
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JS, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JS, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = FLAG_SF;
|
||||
@@ -133,7 +146,8 @@ DEF_SEM(JS, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst)
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JO, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JO, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = FLAG_OF;
|
||||
@@ -142,7 +156,8 @@ DEF_SEM(JO, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst)
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JB, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JB, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = FLAG_CF;
|
||||
@@ -151,7 +166,8 @@ DEF_SEM(JB, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst)
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JLE, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JLE, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = BOr(FLAG_ZF, BXor(FLAG_SF, FLAG_OF));
|
||||
@@ -276,7 +292,8 @@ DEF_ISEL(JLE_RELBRd) = JLE;
|
||||
|
||||
namespace {
|
||||
|
||||
DEF_SEM(JCXZ, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JCXZ, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = UCmpEq(REG_CX, 0_u16);
|
||||
@@ -285,7 +302,8 @@ DEF_SEM(JCXZ, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(JECXZ, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JECXZ, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = UCmpEq(REG_ECX, 0_u32);
|
||||
@@ -295,7 +313,8 @@ DEF_SEM(JECXZ, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_ds
|
||||
}
|
||||
|
||||
#if 64 == ADDRESS_SIZE_BITS
|
||||
DEF_SEM(JRCXZ, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(JRCXZ, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
auto take_branch = UCmpEq(REG_RCX, 0_u64);
|
||||
@@ -305,7 +324,8 @@ DEF_SEM(JRCXZ, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_ds
|
||||
}
|
||||
#endif // 64 == ADDRESS_SIZE_BITS
|
||||
|
||||
DEF_SEM(LOOP, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(LOOP, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
addr_t count = USub(REG_XCX, addr_t(1));
|
||||
@@ -316,7 +336,8 @@ DEF_SEM(LOOP, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(LOOPE, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(LOOPE, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
addr_t count = USub(REG_XCX, addr_t(1));
|
||||
@@ -327,7 +348,8 @@ DEF_SEM(LOOPE, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_ds
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(LOOPNE, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(LOOPNE, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
addr_t taken_pc = Read(taken);
|
||||
addr_t not_taken_pc = Read(not_taken);
|
||||
addr_t count = USub(REG_XCX, addr_t(1));
|
||||
|
||||
@@ -102,8 +102,7 @@ template <typename D, typename S1, size_t num_to_convert>
|
||||
DEF_SEM(CVTDQ2PD, D dst, S1 src) {
|
||||
auto src_vec = SReadV32(src);
|
||||
auto dst_vec = FClearV64(FReadV64(dst));
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < num_to_convert; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < num_to_convert; ++i) {
|
||||
auto entry = Float64(SExtractV32(src_vec, i));
|
||||
dst_vec = FInsertV64(dst_vec, i, entry);
|
||||
}
|
||||
@@ -129,8 +128,7 @@ template <typename D, typename S1, size_t num_to_convert>
|
||||
DEF_SEM(CVTDQ2PS, D dst, S1 src) {
|
||||
auto src_vec = SReadV32(src);
|
||||
auto dst_vec = FClearV32(FReadV32(dst));
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < num_to_convert; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < num_to_convert; ++i) {
|
||||
auto entry = Float32(SExtractV32(src_vec, i));
|
||||
dst_vec = FInsertV32(dst_vec, i, entry);
|
||||
}
|
||||
@@ -154,8 +152,7 @@ template <typename D, typename S1, size_t num_to_convert,
|
||||
DEF_SEM(CVTPD2DQ, D dst, S1 src) {
|
||||
auto src_vec = FReadV64(src);
|
||||
auto dst_vec = SClearV32(SReadV32(dst));
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < num_to_convert; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < num_to_convert; ++i) {
|
||||
float64_t rounded_elem = FRound(FExtractV64(src_vec, i));
|
||||
auto entry = Float64ToInt32(rounded_elem);
|
||||
dst_vec = SInsertV32(dst_vec, i, entry);
|
||||
@@ -175,10 +172,14 @@ IF_AVX(DEF_ISEL(VCVTPD2DQ_XMMdq_YMMqq) = CVTPD2DQ<VV128W, V256, 4>;)
|
||||
|
||||
DEF_ISEL(CVTTPD2DQ_XMMdq_MEMpd) = CVTPD2DQ<V128W, MV128, 2, FTruncTowardZero64>;
|
||||
DEF_ISEL(CVTTPD2DQ_XMMdq_XMMpd) = CVTPD2DQ<V128W, V128, 2, FTruncTowardZero64>;
|
||||
IF_AVX(DEF_ISEL(VCVTTPD2DQ_XMMdq_MEMdq) = CVTPD2DQ<VV128W, MV128, 2, FTruncTowardZero64>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPD2DQ_XMMdq_XMMdq) = CVTPD2DQ<VV128W, V128, 2, FTruncTowardZero64>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPD2DQ_XMMdq_MEMqq) = CVTPD2DQ<VV128W, MV256, 4, FTruncTowardZero64>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPD2DQ_XMMdq_YMMqq) = CVTPD2DQ<VV128W, V256, 4, FTruncTowardZero64>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPD2DQ_XMMdq_MEMdq) =
|
||||
CVTPD2DQ<VV128W, MV128, 2, FTruncTowardZero64>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPD2DQ_XMMdq_XMMdq) =
|
||||
CVTPD2DQ<VV128W, V128, 2, FTruncTowardZero64>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPD2DQ_XMMdq_MEMqq) =
|
||||
CVTPD2DQ<VV128W, MV256, 4, FTruncTowardZero64>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPD2DQ_XMMdq_YMMqq) =
|
||||
CVTPD2DQ<VV128W, V256, 4, FTruncTowardZero64>;)
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -187,8 +188,7 @@ template <typename D, typename S1, size_t num_to_convert,
|
||||
DEF_SEM(CVTPS2DQ, D dst, S1 src) {
|
||||
auto src_vec = FReadV32(src);
|
||||
auto dst_vec = SClearV32(SReadV32(dst));
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < num_to_convert; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < num_to_convert; ++i) {
|
||||
float32_t rounded_elem = FRound(FExtractV32(src_vec, i));
|
||||
dst_vec = SInsertV32(dst_vec, i, Float32ToInt32(rounded_elem));
|
||||
}
|
||||
@@ -207,10 +207,14 @@ IF_AVX(DEF_ISEL(VCVTPS2DQ_YMMqq_YMMqq) = CVTPS2DQ<VV256W, V256, 8>;)
|
||||
|
||||
DEF_ISEL(CVTTPS2DQ_XMMdq_MEMps) = CVTPS2DQ<V128W, MV128, 4, FTruncTowardZero32>;
|
||||
DEF_ISEL(CVTTPS2DQ_XMMdq_XMMps) = CVTPS2DQ<V128W, V128, 4, FTruncTowardZero32>;
|
||||
IF_AVX(DEF_ISEL(VCVTTPS2DQ_XMMdq_MEMdq) = CVTPS2DQ<VV128W, MV128, 4, FTruncTowardZero32>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPS2DQ_XMMdq_XMMdq) = CVTPS2DQ<VV128W, V128, 4, FTruncTowardZero32>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPS2DQ_YMMqq_MEMqq) = CVTPS2DQ<VV256W, MV256, 8, FTruncTowardZero32>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPS2DQ_YMMqq_YMMqq) = CVTPS2DQ<VV256W, V256, 8, FTruncTowardZero32>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPS2DQ_XMMdq_MEMdq) =
|
||||
CVTPS2DQ<VV128W, MV128, 4, FTruncTowardZero32>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPS2DQ_XMMdq_XMMdq) =
|
||||
CVTPS2DQ<VV128W, V128, 4, FTruncTowardZero32>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPS2DQ_YMMqq_MEMqq) =
|
||||
CVTPS2DQ<VV256W, MV256, 8, FTruncTowardZero32>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTPS2DQ_YMMqq_YMMqq) =
|
||||
CVTPS2DQ<VV256W, V256, 8, FTruncTowardZero32>;)
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -243,12 +247,18 @@ IF_AVX(IF_64BIT(DEF_ISEL(VCVTSS2SI_GPR64q_XMMd) = CVTSS2SI_64<V128>;))
|
||||
|
||||
DEF_ISEL(CVTTSS2SI_GPR32d_MEMss) = CVTSS2SI_32<MV32, FTruncTowardZero32>;
|
||||
DEF_ISEL(CVTTSS2SI_GPR32d_XMMss) = CVTSS2SI_32<V128, FTruncTowardZero32>;
|
||||
IF_64BIT(DEF_ISEL(CVTTSS2SI_GPR64q_MEMss) = CVTSS2SI_64<MV32, FTruncTowardZero32>;)
|
||||
IF_64BIT(DEF_ISEL(CVTTSS2SI_GPR64q_XMMss) = CVTSS2SI_64<V128, FTruncTowardZero32>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTSS2SI_GPR32d_MEMd) = CVTSS2SI_32<MV32, FTruncTowardZero32>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTSS2SI_GPR32d_XMMd) = CVTSS2SI_32<V128, FTruncTowardZero32>;)
|
||||
IF_AVX(IF_64BIT(DEF_ISEL(VCVTTSS2SI_GPR64q_MEMd) =CVTSS2SI_64<MV32, FTruncTowardZero32>;))
|
||||
IF_AVX(IF_64BIT(DEF_ISEL(VCVTTSS2SI_GPR64q_XMMd) =CVTSS2SI_64<V128, FTruncTowardZero32>;))
|
||||
IF_64BIT(
|
||||
DEF_ISEL(CVTTSS2SI_GPR64q_MEMss) = CVTSS2SI_64<MV32, FTruncTowardZero32>;)
|
||||
IF_64BIT(
|
||||
DEF_ISEL(CVTTSS2SI_GPR64q_XMMss) = CVTSS2SI_64<V128, FTruncTowardZero32>;)
|
||||
IF_AVX(
|
||||
DEF_ISEL(VCVTTSS2SI_GPR32d_MEMd) = CVTSS2SI_32<MV32, FTruncTowardZero32>;)
|
||||
IF_AVX(
|
||||
DEF_ISEL(VCVTTSS2SI_GPR32d_XMMd) = CVTSS2SI_32<V128, FTruncTowardZero32>;)
|
||||
IF_AVX(IF_64BIT(
|
||||
DEF_ISEL(VCVTTSS2SI_GPR64q_MEMd) = CVTSS2SI_64<MV32, FTruncTowardZero32>;))
|
||||
IF_AVX(IF_64BIT(
|
||||
DEF_ISEL(VCVTTSS2SI_GPR64q_XMMd) = CVTSS2SI_64<V128, FTruncTowardZero32>;))
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -280,20 +290,26 @@ IF_AVX(IF_64BIT(DEF_ISEL(VCVTSD2SI_GPR64q_XMMq) = CVTSD2SI_64<V128>;))
|
||||
|
||||
DEF_ISEL(CVTTSD2SI_GPR32d_MEMsd) = CVTSD2SI_32<MV64, FTruncTowardZero64>;
|
||||
DEF_ISEL(CVTTSD2SI_GPR32d_XMMsd) = CVTSD2SI_32<V128, FTruncTowardZero64>;
|
||||
IF_AVX(DEF_ISEL(VCVTTSD2SI_GPR32d_MEMq) = CVTSD2SI_32<MV64, FTruncTowardZero64>;)
|
||||
IF_AVX(DEF_ISEL(VCVTTSD2SI_GPR32d_XMMq) = CVTSD2SI_32<V128, FTruncTowardZero64>;)
|
||||
IF_64BIT(DEF_ISEL(CVTTSD2SI_GPR64q_MEMsd) = CVTSD2SI_64<MV64, FTruncTowardZero64>;)
|
||||
IF_64BIT(DEF_ISEL(CVTTSD2SI_GPR64q_XMMsd) = CVTSD2SI_64<V128, FTruncTowardZero64>;)
|
||||
IF_AVX(IF_64BIT(DEF_ISEL(VCVTTSD2SI_GPR64q_MEMq) =CVTSD2SI_64<MV64, FTruncTowardZero64>;))
|
||||
IF_AVX(IF_64BIT(DEF_ISEL(VCVTTSD2SI_GPR64q_XMMq) =CVTSD2SI_64<V128, FTruncTowardZero64>;))
|
||||
IF_AVX(
|
||||
DEF_ISEL(VCVTTSD2SI_GPR32d_MEMq) = CVTSD2SI_32<MV64, FTruncTowardZero64>;)
|
||||
IF_AVX(
|
||||
DEF_ISEL(VCVTTSD2SI_GPR32d_XMMq) = CVTSD2SI_32<V128, FTruncTowardZero64>;)
|
||||
IF_64BIT(
|
||||
DEF_ISEL(CVTTSD2SI_GPR64q_MEMsd) = CVTSD2SI_64<MV64, FTruncTowardZero64>;)
|
||||
IF_64BIT(
|
||||
DEF_ISEL(CVTTSD2SI_GPR64q_XMMsd) = CVTSD2SI_64<V128, FTruncTowardZero64>;)
|
||||
IF_AVX(IF_64BIT(
|
||||
DEF_ISEL(VCVTTSD2SI_GPR64q_MEMq) = CVTSD2SI_64<MV64, FTruncTowardZero64>;))
|
||||
IF_AVX(IF_64BIT(
|
||||
DEF_ISEL(VCVTTSD2SI_GPR64q_XMMq) = CVTSD2SI_64<V128, FTruncTowardZero64>;))
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename S1>
|
||||
DEF_SEM(CVTSD2SS, V128W dst, S1 src) {
|
||||
FWriteV32(dst, FInsertV32(
|
||||
FReadV32(dst), 0, Float32(FExtractV64(FReadV64(src), 0))));
|
||||
FWriteV32(dst, FInsertV32(FReadV32(dst), 0,
|
||||
Float32(FExtractV64(FReadV64(src), 0))));
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -399,8 +415,7 @@ template <typename D, typename S1, size_t vec_count>
|
||||
DEF_SEM(CVTPS2PD, D dst, S1 src) {
|
||||
auto src_vec = FReadV32(src);
|
||||
auto dst_vec = FClearV64(FReadV64(dst));
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; ++i) {
|
||||
auto conv_val = Float64(FExtractV32(src_vec, i));
|
||||
dst_vec = FInsertV64(dst_vec, i, conv_val);
|
||||
}
|
||||
@@ -412,8 +427,7 @@ template <typename D, typename S1, size_t vec_count>
|
||||
DEF_SEM(CVTPD2PS, D dst, S1 src) {
|
||||
auto src_vec = FReadV64(src);
|
||||
auto dst_vec = FClearV32(FReadV32(dst));
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; ++i) {
|
||||
auto conv_val = Float32(FExtractV64(src_vec, i));
|
||||
dst_vec = FInsertV32(dst_vec, i, conv_val);
|
||||
}
|
||||
|
||||
@@ -89,9 +89,7 @@ DEF_SEM(MOVLPS, D dst, S src) {
|
||||
auto src_vec = FReadV32(src);
|
||||
auto low1 = FExtractV32(src_vec, 0);
|
||||
auto low2 = FExtractV32(src_vec, 1);
|
||||
FWriteV32(dst, FInsertV32(
|
||||
FInsertV32(FReadV32(dst), 0, low1),
|
||||
1, low2));
|
||||
FWriteV32(dst, FInsertV32(FInsertV32(FReadV32(dst), 0, low1), 1, low2));
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -121,23 +119,14 @@ DEF_SEM(MOVLPD, D dst, S src) {
|
||||
|
||||
DEF_SEM(VMOVLPS, VV128W dst, V128 src1, MV64 src2) {
|
||||
auto low_vec = FReadV32(src2);
|
||||
FWriteV32(dst,
|
||||
FInsertV32(
|
||||
FInsertV32(
|
||||
FReadV32(src1),
|
||||
0,
|
||||
FExtractV32(low_vec, 0)),
|
||||
1,
|
||||
FWriteV32(
|
||||
dst, FInsertV32(FInsertV32(FReadV32(src1), 0, FExtractV32(low_vec, 0)), 1,
|
||||
FExtractV32(low_vec, 1)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(VMOVLPD, VV128W dst, V128 src1, MV64 src2) {
|
||||
FWriteV64(dst,
|
||||
FInsertV64(
|
||||
FReadV64(src1),
|
||||
0,
|
||||
FExtractV64(FReadV64(src2), 0)));
|
||||
FWriteV64(dst, FInsertV64(FReadV64(src1), 0, FExtractV64(FReadV64(src2), 0)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -181,7 +170,8 @@ DEF_ISEL_RnW_Mn(MOV_OrAX_MEMv, MOV);
|
||||
DEF_ISEL(MOV_MEMb_AL) = MOV<M8W, R8>;
|
||||
DEF_ISEL_MnW_Rn(MOV_MEMv_OrAX, MOV);
|
||||
DEF_ISEL(MOV_GPR8_IMMb_D0) = MOV<R8W, I8>;
|
||||
DEF_ISEL(MOV_GPR8_IMMb_B0) = MOV<R8W, I8>; // https://github.com/intelxed/xed/commit/906d25
|
||||
DEF_ISEL(MOV_GPR8_IMMb_B0) =
|
||||
MOV<R8W, I8>; // https://github.com/intelxed/xed/commit/906d25
|
||||
DEF_ISEL_RnW_In(MOV_GPRv_IMMv, MOV);
|
||||
|
||||
DEF_ISEL(MOVNTI_MEMd_GPR32) = MOV<M32W, R32>;
|
||||
@@ -268,6 +258,7 @@ DEF_ISEL(VMOVAPS_YMMqq_YMMqq_28) = MOVxPS<VV256W, VV256>;
|
||||
DEF_ISEL(VMOVAPS_MEMqq_YMMqq) = MOVxPS<MV256W, VV256>;
|
||||
DEF_ISEL(VMOVAPS_YMMqq_YMMqq_29) = MOVxPS<VV256W, VV256>;
|
||||
# if HAS_FEATURE_AVX512
|
||||
|
||||
//4102 VMOVAPS VMOVAPS_ZMMf32_MASKmskw_ZMMf32_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: MASKOP_EVEX
|
||||
//4103 VMOVAPS VMOVAPS_ZMMf32_MASKmskw_MEMf32_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: AVX_REQUIRES_ALIGNMENT DISP8_FULLMEM MASKOP_EVEX MEMORY_FAULT_SUPPRESSION REQUIRES_ALIGNMENT
|
||||
//4104 VMOVAPS VMOVAPS_ZMMf32_MASKmskw_ZMMf32_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: MASKOP_EVEX
|
||||
@@ -289,6 +280,7 @@ DEF_ISEL(MOVNTPS_MEMdq_XMMps) = MOVxPS<MV128W, V128>;
|
||||
DEF_ISEL(VMOVNTPS_MEMdq_XMMdq) = MOVxPS<MV128W, VV128>;
|
||||
DEF_ISEL(VMOVNTPS_MEMqq_YMMqq) = MOVxPS<MV256W, VV256>;
|
||||
# if HAS_FEATURE_AVX512
|
||||
|
||||
//6168 VMOVNTPS VMOVNTPS_MEMf32_ZMMf32_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: DISP8_FULLMEM NOTSX REQUIRES_ALIGNMENT
|
||||
//6169 VMOVNTPS VMOVNTPS_MEMf32_XMMf32_AVX512 DATAXFER AVX512EVEX AVX512F_128 ATTRIBUTES: DISP8_FULLMEM NOTSX REQUIRES_ALIGNMENT
|
||||
//6170 VMOVNTPS VMOVNTPS_MEMf32_YMMf32_AVX512 DATAXFER AVX512EVEX AVX512F_256 ATTRIBUTES: DISP8_FULLMEM NOTSX REQUIRES_ALIGNMENT
|
||||
@@ -310,6 +302,7 @@ DEF_ISEL(VMOVUPS_YMMqq_YMMqq_10) = MOVxPS<VV256W, VV256>;
|
||||
DEF_ISEL(VMOVUPS_MEMqq_YMMqq) = MOVxPS<MV256W, VV256>;
|
||||
DEF_ISEL(VMOVUPS_YMMqq_YMMqq_11) = MOVxPS<VV256W, VV256>;
|
||||
# if HAS_FEATURE_AVX512
|
||||
|
||||
//4954 VMOVUPS VMOVUPS_ZMMf32_MASKmskw_ZMMf32_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: MASKOP_EVEX
|
||||
//4955 VMOVUPS VMOVUPS_ZMMf32_MASKmskw_MEMf32_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: DISP8_FULLMEM MASKOP_EVEX MEMORY_FAULT_SUPPRESSION
|
||||
//4956 VMOVUPS VMOVUPS_ZMMf32_MASKmskw_ZMMf32_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: MASKOP_EVEX
|
||||
@@ -340,6 +333,7 @@ DEF_ISEL(VMOVAPD_YMMqq_YMMqq_28) = MOVxPD<VV256W, VV256>;
|
||||
DEF_ISEL(VMOVAPD_MEMqq_YMMqq) = MOVxPD<MV256W, VV256>;
|
||||
DEF_ISEL(VMOVAPD_YMMqq_YMMqq_29) = MOVxPD<VV256W, VV256>;
|
||||
# if HAS_FEATURE_AVX512
|
||||
|
||||
//5585 VMOVAPD VMOVAPD_ZMMf64_MASKmskw_ZMMf64_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: MASKOP_EVEX
|
||||
//5586 VMOVAPD VMOVAPD_ZMMf64_MASKmskw_MEMf64_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: AVX_REQUIRES_ALIGNMENT DISP8_FULLMEM MASKOP_EVEX MEMORY_FAULT_SUPPRESSION REQUIRES_ALIGNMENT
|
||||
//5587 VMOVAPD VMOVAPD_ZMMf64_MASKmskw_ZMMf64_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: MASKOP_EVEX
|
||||
@@ -361,6 +355,7 @@ DEF_ISEL(MOVNTPD_MEMdq_XMMpd) = MOVxPD<MV128W, V128>;
|
||||
DEF_ISEL(VMOVNTPD_MEMdq_XMMdq) = MOVxPD<MV128W, VV128>;
|
||||
DEF_ISEL(VMOVNTPD_MEMqq_YMMqq) = MOVxPD<MV256W, VV256>;
|
||||
# if HAS_FEATURE_AVX512
|
||||
|
||||
//6088 VMOVNTPD VMOVNTPD_MEMf64_ZMMf64_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: AVX_REQUIRES_ALIGNMENT DISP8_FULLMEM NOTSX REQUIRES_ALIGNMENT
|
||||
//6089 VMOVNTPD VMOVNTPD_MEMf64_XMMf64_AVX512 DATAXFER AVX512EVEX AVX512F_128 ATTRIBUTES: AVX_REQUIRES_ALIGNMENT DISP8_FULLMEM NOTSX REQUIRES_ALIGNMENT
|
||||
//6090 VMOVNTPD VMOVNTPD_MEMf64_YMMf64_AVX512 DATAXFER AVX512EVEX AVX512F_256 ATTRIBUTES: AVX_REQUIRES_ALIGNMENT DISP8_FULLMEM NOTSX REQUIRES_ALIGNMENT
|
||||
@@ -382,6 +377,7 @@ DEF_ISEL(VMOVUPD_YMMqq_YMMqq_10) = MOVxPD<VV256W, VV256>;
|
||||
DEF_ISEL(VMOVUPD_MEMqq_YMMqq) = MOVxPD<MV256W, VV256>;
|
||||
DEF_ISEL(VMOVUPD_YMMqq_YMMqq_11) = MOVxPD<VV256W, VV256>;
|
||||
# if HAS_FEATURE_AVX512
|
||||
|
||||
//4991 VMOVUPD VMOVUPD_ZMMf64_MASKmskw_ZMMf64_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: MASKOP_EVEX
|
||||
//4992 VMOVUPD VMOVUPD_ZMMf64_MASKmskw_MEMf64_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: DISP8_FULLMEM MASKOP_EVEX MEMORY_FAULT_SUPPRESSION
|
||||
//4993 VMOVUPD VMOVUPD_ZMMf64_MASKmskw_ZMMf64_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: MASKOP_EVEX
|
||||
@@ -408,12 +404,14 @@ DEF_ISEL(MOVDQU_XMMdq_XMMdq_0F7F) = MOVDQx<V128W, V128>;
|
||||
#if HAS_FEATURE_AVX
|
||||
DEF_ISEL(VMOVNTDQ_MEMdq_XMMdq) = MOVDQx<MV128W, V128>;
|
||||
DEF_ISEL(VMOVNTDQ_MEMqq_YMMqq) = MOVDQx<MV256W, VV256>;
|
||||
|
||||
//5061 VMOVNTDQ VMOVNTDQ_MEMu32_ZMMu32_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: DISP8_FULLMEM NOTSX REQUIRES_ALIGNMENT
|
||||
//5062 VMOVNTDQ VMOVNTDQ_MEMu32_XMMu32_AVX512 DATAXFER AVX512EVEX AVX512F_128 ATTRIBUTES: DISP8_FULLMEM NOTSX REQUIRES_ALIGNMENT
|
||||
//5063 VMOVNTDQ VMOVNTDQ_MEMu32_YMMu32_AVX512 DATAXFER AVX512EVEX AVX512F_256 ATTRIBUTES: DISP8_FULLMEM NOTSX REQUIRES_ALIGNMENT
|
||||
|
||||
DEF_ISEL(VMOVNTDQA_XMMdq_MEMdq) = MOVDQx<VV128W, MV128>;
|
||||
DEF_ISEL(VMOVNTDQA_YMMqq_MEMqq) = MOVDQx<VV256W, MV256>;
|
||||
|
||||
//4142 VMOVNTDQA VMOVNTDQA_ZMMu32_MEMu32_AVX512 DATAXFER AVX512EVEX AVX512F_512 ATTRIBUTES: DISP8_FULLMEM NOTSX REQUIRES_ALIGNMENT
|
||||
//4143 VMOVNTDQA VMOVNTDQA_XMMu32_MEMu32_AVX512 DATAXFER AVX512EVEX AVX512F_128 ATTRIBUTES: DISP8_FULLMEM NOTSX REQUIRES_ALIGNMENT
|
||||
//4144 VMOVNTDQA VMOVNTDQA_YMMu32_MEMu32_AVX512 DATAXFER AVX512EVEX AVX512F_256 ATTRIBUTES: DISP8_FULLMEM NOTSX REQUIRES_ALIGNMENT
|
||||
@@ -454,6 +452,7 @@ IF_AVX(DEF_ISEL(VMOVLHPS_XMMdq_XMMq_XMMq) = VMOVLHPS;)
|
||||
|
||||
#if HAS_FEATURE_AVX
|
||||
# if HAS_FEATURE_AVX512
|
||||
|
||||
//4606 VMOVLPS DATAXFER AVX512EVEX AVX512F_128N ATTRIBUTES: DISP8_TUPLE2
|
||||
//4607 VMOVLPS VMOVLPS_MEMf32_XMMf32_AVX512 DATAXFER AVX512EVEX AVX512F_128N ATTRIBUTES: DISP8_TUPLE2
|
||||
# endif // HAS_FEATURE_AVX512
|
||||
@@ -466,6 +465,7 @@ IF_AVX(DEF_ISEL(VMOVLPD_XMMdq_XMMdq_MEMq) = VMOVLPD;)
|
||||
|
||||
#if HAS_FEATURE_AVX
|
||||
# if HAS_FEATURE_AVX512
|
||||
|
||||
//4599 VMOVLPD VMOVLPD_XMMf64_XMMf64_MEMf64_AVX512 DATAXFER AVX512EVEX AVX512F_128N ATTRIBUTES: DISP8_SCALAR
|
||||
//4600 VMOVLPD VMOVLPD_MEMf64_XMMf64_AVX512 DATAXFER AVX512EVEX AVX512F_128N ATTRIBUTES: DISP8_SCALAR
|
||||
# endif // HAS_FEATURE_AVX512
|
||||
@@ -480,21 +480,14 @@ DEF_SEM(MOVSD_MEM, D dst, S src) {
|
||||
}
|
||||
|
||||
DEF_SEM(MOVSD, V128W dst, V128 src) {
|
||||
FWriteV64(dst,
|
||||
FInsertV64(
|
||||
FReadV64(dst),
|
||||
0,
|
||||
FExtractV64(FReadV64(src), 0)));
|
||||
FWriteV64(dst, FInsertV64(FReadV64(dst), 0, FExtractV64(FReadV64(src), 0)));
|
||||
return memory;
|
||||
}
|
||||
#if HAS_FEATURE_AVX
|
||||
|
||||
// Basically the same as `VMOVLPD`.
|
||||
DEF_SEM(VMOVSD, VV128W dst, V128 src1, V128 src2) {
|
||||
FWriteV64(dst,
|
||||
FInsertV64(
|
||||
FReadV64(src2),
|
||||
1,
|
||||
FExtractV64(FReadV64(src1), 1)));
|
||||
FWriteV64(dst, FInsertV64(FReadV64(src2), 1, FExtractV64(FReadV64(src1), 1)));
|
||||
return memory;
|
||||
}
|
||||
#endif // HAS_FEATURE_AVX
|
||||
@@ -510,6 +503,7 @@ DEF_ISEL(VMOVSD_MEMq_XMMq) = MOVSD_MEM<MV64W, VV128>;
|
||||
DEF_ISEL(VMOVSD_XMMdq_XMMdq_XMMq_10) = VMOVSD;
|
||||
DEF_ISEL(VMOVSD_XMMdq_XMMdq_XMMq_11) = VMOVSD;
|
||||
# if HAS_FEATURE_AVX512
|
||||
|
||||
//3632 VMOVSD VMOVSD_XMMf64_MASKmskw_MEMf64_AVX512 DATAXFER AVX512EVEX AVX512F_SCALAR ATTRIBUTES: DISP8_SCALAR MASKOP_EVEX MEMORY_FAULT_SUPPRESSION SIMD_SCALAR
|
||||
//3633 VMOVSD VMOVSD_MEMf64_MASKmskw_XMMf64_AVX512 DATAXFER AVX512EVEX AVX512F_SCALAR ATTRIBUTES: DISP8_SCALAR MASKOP_EVEX MEMORY_FAULT_SUPPRESSION SIMD_SCALAR
|
||||
//3634 VMOVSD VMOVSD_XMMf64_MASKmskw_XMMf64_XMMf64_AVX512 DATAXFER AVX512EVEX AVX512F_SCALAR ATTRIBUTES: MASKOP_EVEX SIMD_SCALAR
|
||||
@@ -528,21 +522,13 @@ DEF_SEM(MOVSS_MEM, D dst, S src) {
|
||||
}
|
||||
|
||||
DEF_SEM(MOVSS, V128W dst, V128 src) {
|
||||
FWriteV32(dst,
|
||||
FInsertV32(
|
||||
FReadV32(dst),
|
||||
0,
|
||||
FExtractV32(FReadV32(src), 0)));
|
||||
FWriteV32(dst, FInsertV32(FReadV32(dst), 0, FExtractV32(FReadV32(src), 0)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
#if HAS_FEATURE_AVX
|
||||
DEF_SEM(VMOVSS, VV128W dst, V128 src1, V128 src2) {
|
||||
FWriteV32(dst,
|
||||
FInsertV32(
|
||||
FReadV32(src1),
|
||||
0,
|
||||
FExtractV32(FReadV32(src2), 0)));
|
||||
FWriteV32(dst, FInsertV32(FReadV32(src1), 0, FExtractV32(FReadV32(src2), 0)));
|
||||
return memory;
|
||||
}
|
||||
#endif // HAS_FEATURE_AVX
|
||||
@@ -558,6 +544,7 @@ DEF_ISEL(VMOVSS_MEMd_XMMd) = MOVSS_MEM<MV32W, V128>;
|
||||
DEF_ISEL(VMOVSS_XMMdq_XMMdq_XMMd_10) = VMOVSS;
|
||||
DEF_ISEL(VMOVSS_XMMdq_XMMdq_XMMd_11) = VMOVSS;
|
||||
# if HAS_FEATURE_AVX512
|
||||
|
||||
//3650 VMOVSS VMOVSS_XMMf32_MASKmskw_MEMf32_AVX512 DATAXFER AVX512EVEX AVX512F_SCALAR ATTRIBUTES: DISP8_SCALAR MASKOP_EVEX MEMORY_FAULT_SUPPRESSION SIMD_SCALAR
|
||||
//3651 VMOVSS VMOVSS_MEMf32_MASKmskw_XMMf32_AVX512 DATAXFER AVX512EVEX AVX512F_SCALAR ATTRIBUTES: DISP8_SCALAR MASKOP_EVEX MEMORY_FAULT_SUPPRESSION SIMD_SCALAR
|
||||
//3652 VMOVSS VMOVSS_XMMf32_MASKmskw_XMMf32_XMMf32_AVX512 DATAXFER AVX512EVEX AVX512F_SCALAR ATTRIBUTES: MASKOP_EVEX SIMD_SCALAR
|
||||
@@ -646,36 +633,36 @@ namespace {
|
||||
template <typename T>
|
||||
DEF_SEM(MOV_ES, R16W dst, T src) {
|
||||
Write(dst, Read(src));
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86SetSegmentES);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86SetSegmentES);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DEF_SEM(MOV_SS, R16W dst, T src) {
|
||||
Write(dst, Read(src));
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86SetSegmentSS);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86SetSegmentSS);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DEF_SEM(MOV_DS, R16W dst, T src) {
|
||||
Write(dst, Read(src));
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86SetSegmentDS);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86SetSegmentDS);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DEF_SEM(MOV_FS, R16W dst, T src) {
|
||||
Write(dst, Read(src));
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86SetSegmentFS);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86SetSegmentFS);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
DEF_SEM(MOV_GS, R16W dst, T src) {
|
||||
Write(dst, Read(src));
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86SetSegmentGS);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86SetSegmentGS);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -1105,4 +1092,3 @@ IF_64BIT(DEF_ISEL(MOVSXD_GPRv_MEMd_64) = MOVSX<R64W, M32, int64_t>;)
|
||||
IF_64BIT(DEF_ISEL(MOVSXD_GPRv_MEMz_64) = MOVSX<R64W, M32, int64_t>;)
|
||||
IF_64BIT(DEF_ISEL(MOVSXD_GPRv_GPR32_64) = MOVSX<R64W, R32, int64_t>;)
|
||||
IF_64BIT(DEF_ISEL(MOVSXD_GPRv_GPRz_64) = MOVSX<R64W, R32, int64_t>;)
|
||||
|
||||
|
||||
@@ -72,29 +72,29 @@ DEF_SEM(DoLAHF) {
|
||||
}
|
||||
|
||||
DEF_SEM(DoCLAC) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
state.rflag.ac = false;
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(DoSTAC) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
state.rflag.ac = true;
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(DoCLI) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
state.rflag._if = false;
|
||||
return memory;
|
||||
}
|
||||
|
||||
DEF_SEM(DoSTI) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
state.rflag._if = true;
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -20,52 +20,45 @@ namespace {
|
||||
|
||||
// Used to select specializations of flags computations based on what operator
|
||||
// is executed.
|
||||
enum : uint32_t {
|
||||
kLHS = 2415899639U,
|
||||
kRHS = 70623199U
|
||||
};
|
||||
enum : uint32_t { kLHS = 2415899639U, kRHS = 70623199U };
|
||||
|
||||
// Zero flags, tells us whether or not a value is zero.
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool ZeroFlag(T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool ZeroFlag(T res) {
|
||||
return T(0) == res;
|
||||
}
|
||||
|
||||
// Zero flags, tells us whether or not a value is zero.
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool NotZeroFlag(T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool NotZeroFlag(T res) {
|
||||
return T(0) != res;
|
||||
}
|
||||
|
||||
// Sign flag, tells us if a result is signed or unsigned.
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool SignFlag(T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool SignFlag(T res) {
|
||||
return 0 > Signed(res);
|
||||
}
|
||||
|
||||
// Auxiliary carry flag. This is used for binary coded decimal operations and
|
||||
// is the 5th bit (where each binary decimal is 4 bits).
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool AuxCarryFlag(T lhs, T rhs, T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool AuxCarryFlag(T lhs, T rhs, T res) {
|
||||
return ((res ^ lhs ^ rhs) & T(0x10));
|
||||
}
|
||||
|
||||
// Auxiliary carry flag. This is used for binary coded decimal operations and
|
||||
// is the 5th bit (where each binary decimal is 4 bits).
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool AuxCarryFlag(T lhs, T rhs, T carry, T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool AuxCarryFlag(T lhs, T rhs, T carry,
|
||||
T res) {
|
||||
return ((res ^ lhs ^ carry ^ rhs) & T(0x10));
|
||||
}
|
||||
|
||||
// Tests whether there is an even number of bits in the low order byte.
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool ParityFlag(uint8_t r0) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool ParityFlag(uint8_t r0) {
|
||||
return !__builtin_parity(static_cast<unsigned>(r0));
|
||||
|
||||
// auto r1 = r0 >> 1_u8;
|
||||
// auto r2 = r1 >> 1_u8;
|
||||
// auto r3 = r2 >> 1_u8;
|
||||
@@ -79,8 +72,7 @@ ALWAYS_INLINE static bool ParityFlag(uint8_t r0) {
|
||||
|
||||
// Tests whether there is an even number of bits or not.
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool ParityFlag(T x) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool ParityFlag(T x) {
|
||||
return ParityFlag(static_cast<uint8_t>(x));
|
||||
}
|
||||
|
||||
@@ -97,13 +89,10 @@ struct Overflow;
|
||||
template <>
|
||||
struct Overflow<tag_add> {
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Invalid specialization of `Overflow::Flag` for addition.");
|
||||
enum {
|
||||
kSignShift = sizeof(T) * 8 - 1
|
||||
};
|
||||
enum { kSignShift = sizeof(T) * 8 - 1 };
|
||||
|
||||
const T sign_lhs = lhs >> kSignShift;
|
||||
const T sign_rhs = rhs >> kSignShift;
|
||||
@@ -116,14 +105,11 @@ struct Overflow<tag_add> {
|
||||
template <>
|
||||
struct Overflow<tag_sub> {
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Invalid specialization of `Overflow::Flag` for "
|
||||
"subtraction.");
|
||||
enum {
|
||||
kSignShift = sizeof(T) * 8 - 1
|
||||
};
|
||||
enum { kSignShift = sizeof(T) * 8 - 1 };
|
||||
|
||||
const T sign_lhs = lhs >> kSignShift;
|
||||
const T sign_rhs = rhs >> kSignShift;
|
||||
@@ -139,9 +125,8 @@ struct Overflow<tag_mul> {
|
||||
// Integer multiplication overflow check, where result is twice the width of
|
||||
// the operands.
|
||||
template <typename T, typename R>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool Flag(
|
||||
T, T, R res,
|
||||
[[gnu::const]] ALWAYS_INLINE static bool
|
||||
Flag(T, T, R res,
|
||||
typename std::enable_if<sizeof(T) < sizeof(R), int>::type = 0) {
|
||||
|
||||
return static_cast<R>(static_cast<T>(res)) != res;
|
||||
@@ -150,9 +135,8 @@ struct Overflow<tag_mul> {
|
||||
// Signed integer multiplication overflow check, where the result is
|
||||
// truncated to the size of the operands.
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool Flag(
|
||||
T lhs, T rhs, T,
|
||||
[[gnu::const]] ALWAYS_INLINE static bool
|
||||
Flag(T lhs, T rhs, T,
|
||||
typename std::enable_if<std::is_signed<T>::value, int>::type = 0) {
|
||||
auto lhs_wide = SExt(lhs);
|
||||
auto rhs_wide = SExt(rhs);
|
||||
@@ -168,8 +152,7 @@ struct Carry;
|
||||
template <>
|
||||
struct Carry<tag_add> {
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T res) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Invalid specialization of `Carry::Flag` for addition.");
|
||||
return res < lhs || res < rhs;
|
||||
@@ -180,8 +163,7 @@ struct Carry<tag_add> {
|
||||
template <>
|
||||
struct Carry<tag_sub> {
|
||||
template <typename T>
|
||||
[[gnu::const]]
|
||||
ALWAYS_INLINE static bool Flag(T lhs, T rhs, T) {
|
||||
[[gnu::const]] ALWAYS_INLINE static bool Flag(T lhs, T rhs, T) {
|
||||
static_assert(std::is_unsigned<T>::value,
|
||||
"Invalid specialization of `Carry::Flag` for addition.");
|
||||
return lhs < rhs;
|
||||
@@ -211,8 +193,7 @@ ALWAYS_INLINE static void SetFPSRStatusFlags(State &state, int mask) {
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
ALWAYS_INLINE static
|
||||
auto CheckedFloatUnaryOp(State &state, F func, T arg1)
|
||||
ALWAYS_INLINE static auto CheckedFloatUnaryOp(State &state, F func, T arg1)
|
||||
-> decltype(func(arg1)) {
|
||||
state.sw.de = IsDenormal(arg1);
|
||||
auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT);
|
||||
@@ -226,8 +207,8 @@ auto CheckedFloatUnaryOp(State &state, F func, T arg1)
|
||||
}
|
||||
|
||||
template <typename F1, typename F2, typename T>
|
||||
ALWAYS_INLINE static
|
||||
auto CheckedFloatUnaryOp2(State &state, F1 func1, F2 func2, T arg1)
|
||||
ALWAYS_INLINE static auto CheckedFloatUnaryOp2(State &state, F1 func1, F2 func2,
|
||||
T arg1)
|
||||
-> decltype(func2(func1(arg1))) {
|
||||
state.sw.de = IsDenormal(arg1);
|
||||
auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT);
|
||||
@@ -241,16 +222,16 @@ auto CheckedFloatUnaryOp2(State &state, F1 func1, F2 func2, T arg1)
|
||||
BarrierReorder();
|
||||
auto res = func2(res1);
|
||||
BarrierReorder();
|
||||
auto new_except2 = __remill_fpu_exception_test_and_clear(
|
||||
FE_ALL_EXCEPT, new_except1);
|
||||
auto new_except2 =
|
||||
__remill_fpu_exception_test_and_clear(FE_ALL_EXCEPT, new_except1);
|
||||
|
||||
SetFPSRStatusFlags(state, new_except1 | new_except2);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename F, typename T>
|
||||
ALWAYS_INLINE static
|
||||
auto CheckedFloatBinOp(State &state, F func, T arg1, T arg2)
|
||||
ALWAYS_INLINE static auto CheckedFloatBinOp(State &state, F func, T arg1,
|
||||
T arg2)
|
||||
-> decltype(func(arg1, arg2)) {
|
||||
state.sw.de = IsDenormal(arg1) | IsDenormal(arg2);
|
||||
auto old_except = __remill_fpu_exception_test_and_clear(0, FE_ALL_EXCEPT);
|
||||
|
||||
@@ -20,6 +20,7 @@ namespace {
|
||||
|
||||
template <typename D, typename S1, typename S2, typename S3>
|
||||
DEF_SEM(VFMADD132SD, D dst, S1 src1, S2 src2, S3 src3) {
|
||||
|
||||
// Each operand is a vector of 64-bit (QWORD) floats:
|
||||
auto temp_vec = FReadV64(src1); // src1 is also dst
|
||||
auto src3_vec = FReadV64(src3);
|
||||
@@ -40,6 +41,7 @@ DEF_SEM(VFMADD132SD, D dst, S1 src1, S2 src2, S3 src3) {
|
||||
|
||||
template <typename D, typename S1, typename S2, typename S3>
|
||||
DEF_SEM(VFMADD231SD, D dst, S1 src1, S2 src2, S3 src3) {
|
||||
|
||||
// Each operand is a vector of 64-bit (QWORD) floats:
|
||||
auto src2_vec = FReadV64(src2);
|
||||
auto src3_vec = FReadV64(src3);
|
||||
@@ -60,6 +62,7 @@ DEF_SEM(VFMADD231SD, D dst, S1 src1, S2 src2, S3 src3) {
|
||||
|
||||
template <typename D, typename S1, typename S2, typename S3>
|
||||
DEF_SEM(VFMADD213SD, D dst, S1 src1, S2 src2, S3 src3) {
|
||||
|
||||
// Each operand is a vector of 64-bit (QWORD) floats:
|
||||
auto src2_vec = FReadV64(src2);
|
||||
auto temp_vec = FReadV64(src1); // src1 is also dst
|
||||
@@ -101,6 +104,7 @@ namespace {
|
||||
|
||||
template <typename D, typename S1, typename S2, typename S3>
|
||||
DEF_SEM(VFMSUB132SD, D dst, S1 src1, S2 src2, S3 src3) {
|
||||
|
||||
// Each operand is a vector of 64-bit (QWORD) floats:
|
||||
auto temp_vec = FReadV64(src1); // src1 is also dst
|
||||
auto src3_vec = FReadV64(src3);
|
||||
@@ -121,6 +125,7 @@ DEF_SEM(VFMSUB132SD, D dst, S1 src1, S2 src2, S3 src3) {
|
||||
|
||||
template <typename D, typename S1, typename S2, typename S3>
|
||||
DEF_SEM(VFMSUB213SD, D dst, S1 src1, S2 src2, S3 src3) {
|
||||
|
||||
// Each operand is a vector of 64-bit (QWORD) floats:
|
||||
auto src2_vec = FReadV64(src2);
|
||||
auto temp_vec = FReadV64(src1); // src1 is also dst
|
||||
@@ -141,6 +146,7 @@ DEF_SEM(VFMSUB213SD, D dst, S1 src1, S2 src2, S3 src3) {
|
||||
|
||||
template <typename D, typename S1, typename S2, typename S3>
|
||||
DEF_SEM(VFMSUB231SD, D dst, S1 src1, S2 src2, S3 src3) {
|
||||
|
||||
// Each operand is a vector of 64-bit (QWORD) floats:
|
||||
auto src2_vec = FReadV64(src2);
|
||||
auto src3_vec = FReadV64(src3);
|
||||
|
||||
@@ -18,46 +18,46 @@ namespace {
|
||||
|
||||
template <typename S>
|
||||
DEF_SEM(IN8, R8W dst, S port) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
Write(dst, __remill_read_io_port_8(memory, Read(port)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
DEF_SEM(IN16, R16W dst, S port) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
Write(dst, __remill_read_io_port_16(memory, Read(port)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
DEF_SEM(IN32, R32W dst, S port) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
WriteZExt(dst, __remill_read_io_port_32(memory, Read(port)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
DEF_SEM(OUT8, S port, R8 src) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
return __remill_write_io_port_8(memory, Read(port), Read(src));
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
DEF_SEM(OUT16, S port, R16 src) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
return __remill_write_io_port_16(memory, Read(port), Read(src));
|
||||
}
|
||||
|
||||
template <typename S>
|
||||
DEF_SEM(OUT32, S port, R32 src) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
return __remill_write_io_port_32(memory, Read(port), Read(src));
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ DEF_SEM(LEA, D dst, S src) {
|
||||
DEF_SEM(LEAVE_16BIT) {
|
||||
addr_t op_size = 2;
|
||||
addr_t link_pointer = Read(REG_XBP);
|
||||
addr_t base_pointer = Read(
|
||||
ReadPtr<addr_t>(link_pointer _IF_32BIT(REG_SS_BASE)));
|
||||
addr_t base_pointer =
|
||||
Read(ReadPtr<addr_t>(link_pointer _IF_32BIT(REG_SS_BASE)));
|
||||
Write(REG_XBP, base_pointer);
|
||||
Write(REG_XSP, UAdd(link_pointer, op_size));
|
||||
return memory;
|
||||
@@ -38,8 +38,8 @@ template <typename T>
|
||||
DEF_SEM(LEAVE_FULL) {
|
||||
addr_t op_size = TruncTo<addr_t>(sizeof(T));
|
||||
addr_t link_pointer = Read(REG_XBP);
|
||||
addr_t base_pointer = Read(
|
||||
ReadPtr<addr_t>(link_pointer _IF_32BIT(REG_SS_BASE)));
|
||||
addr_t base_pointer =
|
||||
Read(ReadPtr<addr_t>(link_pointer _IF_32BIT(REG_SS_BASE)));
|
||||
Write(REG_XBP, base_pointer);
|
||||
Write(REG_XSP, UAdd(link_pointer, op_size));
|
||||
return memory;
|
||||
@@ -68,9 +68,8 @@ DEF_SEM(ENTER, I16 src1, I8 src2) {
|
||||
addr_t nesting_level = ZExtTo<addr_t>(URem(Read(src2), 32_u8));
|
||||
addr_t xsp_temp = Read(REG_XSP);
|
||||
addr_t frame_temp = USub(xsp_temp, op_size);
|
||||
addr_t next_xsp = USub(
|
||||
USub(frame_temp, UMul(op_size, nesting_level)),
|
||||
alloc_size);
|
||||
addr_t next_xsp =
|
||||
USub(USub(frame_temp, UMul(op_size, nesting_level)), alloc_size);
|
||||
|
||||
// Detect failure. This should really happen at the end of `ENTER` but we
|
||||
// do it here. This is why `frame_temp` is created before the `PUSH` of
|
||||
@@ -88,8 +87,7 @@ DEF_SEM(ENTER, I16 src1, I8 src2) {
|
||||
|
||||
if (nesting_level) {
|
||||
if (1 < nesting_level) {
|
||||
_Pragma("unroll")
|
||||
for (addr_t i = 1; i <= (nesting_level - 1); ++i) {
|
||||
_Pragma("unroll") for (addr_t i = 1; i <= (nesting_level - 1); ++i) {
|
||||
xbp_temp = USub(xbp_temp, op_size); // TODO(pag): Handle 67H prefix.
|
||||
|
||||
// Copy the display entry to the stack.
|
||||
@@ -151,8 +149,8 @@ DEF_SEM(DoLFENCE) {
|
||||
DEF_SEM(DoXLAT) {
|
||||
addr_t base = Read(REG_XBX);
|
||||
addr_t offset = ZExtTo<addr_t>(Read(REG_AL));
|
||||
Write(REG_AL, Read(
|
||||
ReadPtr<uint8_t>(UAdd(base, offset) _IF_32BIT(REG_DS_BASE))));
|
||||
Write(REG_AL,
|
||||
Read(ReadPtr<uint8_t>(UAdd(base, offset) _IF_32BIT(REG_DS_BASE))));
|
||||
return memory;
|
||||
}
|
||||
|
||||
|
||||
+195
-298
@@ -24,12 +24,12 @@ DEF_SEM(PUNPCKHBW, D dst, S1 src1, S2 src2) {
|
||||
auto src2_vec = UReadV8(src2);
|
||||
auto dst_vec = UClearV8(UReadV8(dst));
|
||||
auto num_elems = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0, j = num_elems; i < (num_elems / 2); ++i, j -= 2) {
|
||||
dst_vec = UInsertV8(
|
||||
dst_vec, j - 1, UExtractV8(src2_vec, (num_elems-1) - i));
|
||||
dst_vec = UInsertV8(
|
||||
dst_vec, j - 2, UExtractV8(src1_vec, (num_elems-1) - i));
|
||||
_Pragma("unroll") for (size_t i = 0, j = num_elems; i < (num_elems / 2);
|
||||
++i, j -= 2) {
|
||||
dst_vec =
|
||||
UInsertV8(dst_vec, j - 1, UExtractV8(src2_vec, (num_elems - 1) - i));
|
||||
dst_vec =
|
||||
UInsertV8(dst_vec, j - 2, UExtractV8(src1_vec, (num_elems - 1) - i));
|
||||
}
|
||||
UWriteV8(dst, dst_vec);
|
||||
return memory;
|
||||
@@ -41,12 +41,12 @@ DEF_SEM(PUNPCKHWD, D dst, S1 src1, S2 src2) {
|
||||
auto src2_vec = UReadV16(src2);
|
||||
auto dst_vec = UClearV16(UReadV16(dst));
|
||||
auto num_elems = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0, j = num_elems; i < (num_elems / 2); ++i, j -= 2) {
|
||||
dst_vec = UInsertV16(
|
||||
dst_vec, j - 1, UExtractV16(src2_vec, (num_elems-1) - i));
|
||||
dst_vec = UInsertV16(
|
||||
dst_vec, j - 2, UExtractV16(src1_vec, (num_elems-1) - i));
|
||||
_Pragma("unroll") for (size_t i = 0, j = num_elems; i < (num_elems / 2);
|
||||
++i, j -= 2) {
|
||||
dst_vec =
|
||||
UInsertV16(dst_vec, j - 1, UExtractV16(src2_vec, (num_elems - 1) - i));
|
||||
dst_vec =
|
||||
UInsertV16(dst_vec, j - 2, UExtractV16(src1_vec, (num_elems - 1) - i));
|
||||
}
|
||||
UWriteV16(dst, dst_vec);
|
||||
return memory;
|
||||
@@ -58,12 +58,12 @@ DEF_SEM(PUNPCKHDQ, D dst, S1 src1, S2 src2) {
|
||||
auto src2_vec = UReadV32(src2);
|
||||
auto dst_vec = UClearV32(UReadV32(dst));
|
||||
auto num_elems = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0, j = num_elems; i < (num_elems / 2); ++i, j -= 2) {
|
||||
dst_vec = UInsertV32(
|
||||
dst_vec, j - 1, UExtractV32(src2_vec, (num_elems-1) - i));
|
||||
dst_vec = UInsertV32(
|
||||
dst_vec, j - 2, UExtractV32(src1_vec, (num_elems-1) - i));
|
||||
_Pragma("unroll") for (size_t i = 0, j = num_elems; i < (num_elems / 2);
|
||||
++i, j -= 2) {
|
||||
dst_vec =
|
||||
UInsertV32(dst_vec, j - 1, UExtractV32(src2_vec, (num_elems - 1) - i));
|
||||
dst_vec =
|
||||
UInsertV32(dst_vec, j - 2, UExtractV32(src1_vec, (num_elems - 1) - i));
|
||||
}
|
||||
UWriteV32(dst, dst_vec);
|
||||
return memory;
|
||||
@@ -75,12 +75,12 @@ DEF_SEM(PUNPCKHQDQ, D dst, S1 src1, S2 src2) {
|
||||
auto src2_vec = UReadV64(src2);
|
||||
auto dst_vec = UClearV64(UReadV64(dst));
|
||||
auto num_elems = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0, j = num_elems; i < (num_elems / 2); ++i, j -= 2) {
|
||||
dst_vec = UInsertV64(
|
||||
dst_vec, j - 1, UExtractV64(src2_vec, (num_elems-1) - i));
|
||||
dst_vec = UInsertV64(
|
||||
dst_vec, j - 2, UExtractV64(src1_vec, (num_elems-1) - i));
|
||||
_Pragma("unroll") for (size_t i = 0, j = num_elems; i < (num_elems / 2);
|
||||
++i, j -= 2) {
|
||||
dst_vec =
|
||||
UInsertV64(dst_vec, j - 1, UExtractV64(src2_vec, (num_elems - 1) - i));
|
||||
dst_vec =
|
||||
UInsertV64(dst_vec, j - 2, UExtractV64(src1_vec, (num_elems - 1) - i));
|
||||
}
|
||||
UWriteV64(dst, dst_vec);
|
||||
return memory;
|
||||
@@ -92,8 +92,8 @@ DEF_SEM(PUNPCKLBW, D dst, S1 src1, S2 src2) {
|
||||
auto src2_vec = UReadV8(src2);
|
||||
auto dst_vec = UClearV8(UReadV8(dst));
|
||||
auto num_elems = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0, j = 0; i < (num_elems / 2); ++i, j += 2) {
|
||||
_Pragma("unroll") for (size_t i = 0, j = 0; i < (num_elems / 2);
|
||||
++i, j += 2) {
|
||||
dst_vec = UInsertV8(dst_vec, j, UExtractV8(src1_vec, i));
|
||||
dst_vec = UInsertV8(dst_vec, j + 1, UExtractV8(src2_vec, i));
|
||||
}
|
||||
@@ -107,8 +107,8 @@ DEF_SEM(PUNPCKLWD, D dst, S1 src1, S2 src2) {
|
||||
auto src2_vec = UReadV16(src2);
|
||||
auto dst_vec = UClearV16(UReadV16(dst));
|
||||
auto num_elems = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0, j = 0; i < (num_elems / 2); ++i, j += 2) {
|
||||
_Pragma("unroll") for (size_t i = 0, j = 0; i < (num_elems / 2);
|
||||
++i, j += 2) {
|
||||
dst_vec = UInsertV16(dst_vec, j, UExtractV16(src1_vec, i));
|
||||
dst_vec = UInsertV16(dst_vec, j + 1, UExtractV16(src2_vec, i));
|
||||
}
|
||||
@@ -122,8 +122,8 @@ DEF_SEM(PUNPCKLDQ, D dst, S1 src1, S2 src2) {
|
||||
auto src2_vec = UReadV32(src2);
|
||||
auto dst_vec = UClearV32(UReadV32(dst));
|
||||
auto num_elems = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0, j = 0; i < (num_elems / 2); ++i, j += 2) {
|
||||
_Pragma("unroll") for (size_t i = 0, j = 0; i < (num_elems / 2);
|
||||
++i, j += 2) {
|
||||
dst_vec = UInsertV32(dst_vec, j, UExtractV32(src1_vec, i));
|
||||
dst_vec = UInsertV32(dst_vec, j + 1, UExtractV32(src2_vec, i));
|
||||
}
|
||||
@@ -137,8 +137,8 @@ DEF_SEM(PUNPCKLQDQ, D dst, S1 src1, S2 src2) {
|
||||
auto src2_vec = UReadV64(src2);
|
||||
auto dst_vec = UClearV64(UReadV64(dst));
|
||||
auto num_elems = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0, j = 0; i < (num_elems / 2); ++i, j += 2) {
|
||||
_Pragma("unroll") for (size_t i = 0, j = 0; i < (num_elems / 2);
|
||||
++i, j += 2) {
|
||||
dst_vec = UInsertV64(dst_vec, j, UExtractV64(src1_vec, i));
|
||||
dst_vec = UInsertV64(dst_vec, j + 1, UExtractV64(src2_vec, i));
|
||||
}
|
||||
@@ -275,8 +275,8 @@ DEF_SEM(PADDSB, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV8(SReadV8(dst));
|
||||
|
||||
// Compute signed saturation arithematic on each bytes
|
||||
_Pragma("unroll")
|
||||
for (size_t index = 0; index < NumVectorElems(src1_vec); index++) {
|
||||
_Pragma("unroll") for (size_t index = 0; index < NumVectorElems(src1_vec);
|
||||
index++) {
|
||||
auto v1 = SExtractV8(src1_vec, index);
|
||||
auto v2 = SExtractV8(src2_vec, index);
|
||||
auto max = SExt(Maximize(v1));
|
||||
@@ -298,8 +298,8 @@ DEF_SEM(PADDSW, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Compute signed saturation arithematic on each bytes
|
||||
auto dst_vec = SClearV16(SReadV16(dst));
|
||||
_Pragma("unroll")
|
||||
for (size_t index = 0; index < NumVectorElems(src1_vec); index++) {
|
||||
_Pragma("unroll") for (size_t index = 0; index < NumVectorElems(src1_vec);
|
||||
index++) {
|
||||
auto v1 = SExtractV16(src1_vec, index);
|
||||
auto v2 = SExtractV16(src2_vec, index);
|
||||
auto max = SExt(Maximize(v1));
|
||||
@@ -335,8 +335,7 @@ DEF_SEM(PADDUSB, D dst, S1 src1, S2 src2) {
|
||||
auto num_groups = NumVectorElems(dst_vec);
|
||||
|
||||
// Compute unsigned saturation arithematic on each bytes
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < num_groups; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < num_groups; ++i) {
|
||||
auto v1 = UExtractV8(src1_vec, i);
|
||||
auto v2 = UExtractV8(src2_vec, i);
|
||||
uint8_t v_sum = v1 + v2;
|
||||
@@ -355,8 +354,7 @@ DEF_SEM(PADDUSW, D dst, S1 src1, S2 src2) {
|
||||
auto num_groups = NumVectorElems(dst_vec);
|
||||
|
||||
// Compute unsigned saturation arithematic on each words
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < num_groups; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < num_groups; ++i) {
|
||||
auto v1 = UExtractV16(src1_vec, i);
|
||||
auto v2 = UExtractV16(src2_vec, i);
|
||||
uint16_t v_sum = v1 + v2;
|
||||
@@ -367,7 +365,7 @@ DEF_SEM(PADDUSW, D dst, S1 src1, S2 src2) {
|
||||
return memory;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
DEF_ISEL(PADDUSB_XMMdq_XMMdq) = PADDUSB<V128W, V128, V128>;
|
||||
DEF_ISEL(PADDUSB_XMMdq_MEMdq) = PADDUSB<V128W, V128, MV128>;
|
||||
@@ -385,15 +383,14 @@ DEF_SEM(PHADDW, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Compute the horizontal packing
|
||||
auto vec_count = NumVectorElems(lhs_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t index = 0; index < vec_count; index += 2) {
|
||||
_Pragma("unroll") for (size_t index = 0; index < vec_count; index += 2) {
|
||||
auto v1 = SExtractV16(lhs_vec, index);
|
||||
auto v2 = SExtractV16(lhs_vec, index + 1);
|
||||
auto i = UDiv(UInt32(index), UInt32(2));
|
||||
dst_vec = SInsertV16(dst_vec, i, SAdd(v1, v2));
|
||||
}
|
||||
_Pragma("unroll")
|
||||
for (size_t index = 0; index < NumVectorElems(rhs_vec); index += 2) {
|
||||
_Pragma("unroll") for (size_t index = 0; index < NumVectorElems(rhs_vec);
|
||||
index += 2) {
|
||||
auto v1 = SExtractV16(rhs_vec, index);
|
||||
auto v2 = SExtractV16(rhs_vec, index + 1);
|
||||
auto i = UAdd(UInt32(index), UInt32(vec_count));
|
||||
@@ -412,15 +409,14 @@ DEF_SEM(PHADDD, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Compute the horizontal packing
|
||||
auto vec_count = NumVectorElems(lhs_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t index = 0; index < vec_count; index += 2) {
|
||||
_Pragma("unroll") for (size_t index = 0; index < vec_count; index += 2) {
|
||||
auto v1 = SExtractV32(lhs_vec, index);
|
||||
auto v2 = SExtractV32(lhs_vec, index + 1);
|
||||
auto i = UDiv(UInt32(index), UInt32(2));
|
||||
dst_vec = SInsertV32(dst_vec, i, SAdd(v1, v2));
|
||||
}
|
||||
_Pragma("unroll")
|
||||
for (size_t index = 0; index < NumVectorElems(rhs_vec); index += 2) {
|
||||
_Pragma("unroll") for (size_t index = 0; index < NumVectorElems(rhs_vec);
|
||||
index += 2) {
|
||||
auto v1 = SExtractV32(rhs_vec, index);
|
||||
auto v2 = SExtractV32(rhs_vec, index + 1);
|
||||
auto i = UDiv(UAdd(UInt32(index), UInt32(vec_count)), UInt32(2));
|
||||
@@ -449,41 +445,36 @@ DEF_SEM(PHADDSW, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV16(SReadV16(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t index = 0; index < vec_count; index += 2) {
|
||||
auto add_elem = SAdd(SExtractV16(src1_vec, index),
|
||||
SExtractV16(src1_vec, index+1));
|
||||
auto or_elem = SOr(SExtractV16(src1_vec, index),
|
||||
SExtractV16(src1_vec, index+1));
|
||||
auto and_elem = SAnd(SExtractV16(src1_vec, index),
|
||||
SExtractV16(src1_vec, index+1));
|
||||
auto tmp = Select(
|
||||
SCmpLt(SAnd(add_elem, SNot(or_elem)), decltype(add_elem)(0)),
|
||||
Maximize(add_elem),
|
||||
add_elem);
|
||||
auto value = Select(
|
||||
SCmpLt(SAnd(SNot(add_elem), and_elem), decltype(add_elem)(0)),
|
||||
decltype(add_elem)(0x8000),
|
||||
tmp);
|
||||
_Pragma("unroll") for (size_t index = 0; index < vec_count; index += 2) {
|
||||
auto add_elem =
|
||||
SAdd(SExtractV16(src1_vec, index), SExtractV16(src1_vec, index + 1));
|
||||
auto or_elem =
|
||||
SOr(SExtractV16(src1_vec, index), SExtractV16(src1_vec, index + 1));
|
||||
auto and_elem =
|
||||
SAnd(SExtractV16(src1_vec, index), SExtractV16(src1_vec, index + 1));
|
||||
auto tmp =
|
||||
Select(SCmpLt(SAnd(add_elem, SNot(or_elem)), decltype(add_elem)(0)),
|
||||
Maximize(add_elem), add_elem);
|
||||
auto value =
|
||||
Select(SCmpLt(SAnd(SNot(add_elem), and_elem), decltype(add_elem)(0)),
|
||||
decltype(add_elem)(0x8000), tmp);
|
||||
dst_vec = SInsertV16(dst_vec, index / 2, value);
|
||||
}
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t index = 0; index < NumVectorElems(src2_vec); index += 2) {
|
||||
auto add_elem = SAdd(SExtractV16(src2_vec, index),
|
||||
SExtractV16(src2_vec, index+1));
|
||||
auto or_elem = SOr(SExtractV16(src2_vec, index),
|
||||
SExtractV16(src2_vec, index+1));
|
||||
auto and_elem = SAnd(SExtractV16(src2_vec, index),
|
||||
SExtractV16(src2_vec, index+1));
|
||||
auto tmp = Select(
|
||||
SCmpLt(SAnd(add_elem, SNot(or_elem)), decltype(add_elem)(0)),
|
||||
Maximize(add_elem),
|
||||
add_elem);
|
||||
auto value = Select(
|
||||
SCmpLt(SAnd(SNot(add_elem), and_elem), decltype(add_elem)(0)),
|
||||
decltype(add_elem)(0x8000),
|
||||
tmp);
|
||||
_Pragma("unroll") for (size_t index = 0; index < NumVectorElems(src2_vec);
|
||||
index += 2) {
|
||||
auto add_elem =
|
||||
SAdd(SExtractV16(src2_vec, index), SExtractV16(src2_vec, index + 1));
|
||||
auto or_elem =
|
||||
SOr(SExtractV16(src2_vec, index), SExtractV16(src2_vec, index + 1));
|
||||
auto and_elem =
|
||||
SAnd(SExtractV16(src2_vec, index), SExtractV16(src2_vec, index + 1));
|
||||
auto tmp =
|
||||
Select(SCmpLt(SAnd(add_elem, SNot(or_elem)), decltype(add_elem)(0)),
|
||||
Maximize(add_elem), add_elem);
|
||||
auto value =
|
||||
Select(SCmpLt(SAnd(SNot(add_elem), and_elem), decltype(add_elem)(0)),
|
||||
decltype(add_elem)(0x8000), tmp);
|
||||
dst_vec = SInsertV16(dst_vec, (index + vec_count) / 2, value);
|
||||
}
|
||||
SWriteV16(dst, dst_vec);
|
||||
@@ -575,8 +566,7 @@ DEF_SEM(PSUBUSB, D dst, S1 src1, S2 src2) {
|
||||
auto rhs_vec = UReadV8(src2);
|
||||
auto dst_vec = UClearV8(UReadV8(dst));
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < NumVectorElems(dst_vec); i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < NumVectorElems(dst_vec); i++) {
|
||||
auto v1 = UExtractV8(lhs_vec, i);
|
||||
auto v2 = UExtractV8(rhs_vec, i);
|
||||
auto sub = USub(v1, v2);
|
||||
@@ -593,8 +583,7 @@ DEF_SEM(PSUBUSW, D dst, S1 src1, S2 src2) {
|
||||
auto rhs_vec = UReadV16(src2);
|
||||
auto dst_vec = UClearV16(UReadV16(dst));
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < NumVectorElems(dst_vec); i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < NumVectorElems(dst_vec); i++) {
|
||||
auto v1 = UExtractV16(lhs_vec, i);
|
||||
auto v2 = UExtractV16(rhs_vec, i);
|
||||
auto sub = USub(v1, v2);
|
||||
@@ -627,8 +616,7 @@ DEF_SEM(PAVGB, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Compute the AVG; The sum can spill to 9th bits
|
||||
auto vec_count = NumVectorElems(lhs_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = UExtractV8(lhs_vec, i);
|
||||
auto v2 = UExtractV8(rhs_vec, i);
|
||||
auto sum_elem = UAdd(ZExt(v1), ZExt(v2));
|
||||
@@ -647,8 +635,7 @@ DEF_SEM(PAVGW, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Compute the AVG; The sum can spill to 17th bits
|
||||
auto vec_count = NumVectorElems(lhs_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = ZExt(UExtractV16(lhs_vec, i));
|
||||
auto v2 = ZExt(UExtractV16(rhs_vec, i));
|
||||
auto sum_elem = UAdd(v1, v2);
|
||||
@@ -679,15 +666,13 @@ DEF_SEM(PHSUBW, D dst, S1 src1, S2 src2) {
|
||||
auto rhs_vec = SReadV16(src2);
|
||||
auto dst_vec = SClearV16(SReadV16(dst));
|
||||
auto vec_count = NumVectorElems(lhs_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i = i+2) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i = i + 2) {
|
||||
auto v1 = SExtractV16(lhs_vec, i);
|
||||
auto v2 = SExtractV16(lhs_vec, i + 1);
|
||||
auto index = UDiv(UInt32(i), UInt32(2));
|
||||
dst_vec = SInsertV16(dst_vec, index, SSub(v1, v2));
|
||||
}
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < NumVectorElems(rhs_vec); i = i+2) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < NumVectorElems(rhs_vec); i = i + 2) {
|
||||
auto v1 = SExtractV16(rhs_vec, i);
|
||||
auto v2 = SExtractV16(rhs_vec, i + 1);
|
||||
auto index = UDiv(UAdd(UInt32(i), UInt32(vec_count)), UInt32(2));
|
||||
@@ -703,21 +688,15 @@ DEF_SEM(PHSUBD, D dst, S1 src1, S2 src2) {
|
||||
auto rhs_vec = SReadV32(src2);
|
||||
auto dst_vec = SClearV32(SReadV32(dst));
|
||||
auto vec_count = NumVectorElems(lhs_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i = i+2) {
|
||||
dst_vec = SInsertV32(
|
||||
dst_vec,
|
||||
i/2,
|
||||
SSub(SExtractV32(lhs_vec, i),
|
||||
SExtractV32(lhs_vec, i+1)));
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i = i + 2) {
|
||||
dst_vec =
|
||||
SInsertV32(dst_vec, i / 2,
|
||||
SSub(SExtractV32(lhs_vec, i), SExtractV32(lhs_vec, i + 1)));
|
||||
}
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < NumVectorElems(rhs_vec); i = i+2) {
|
||||
dst_vec = SInsertV32(
|
||||
dst_vec,
|
||||
(i+vec_count)/2,
|
||||
SSub(SExtractV32(rhs_vec, i),
|
||||
SExtractV32(rhs_vec, i+1)));
|
||||
_Pragma("unroll") for (size_t i = 0; i < NumVectorElems(rhs_vec); i = i + 2) {
|
||||
dst_vec =
|
||||
SInsertV32(dst_vec, (i + vec_count) / 2,
|
||||
SSub(SExtractV32(rhs_vec, i), SExtractV32(rhs_vec, i + 1)));
|
||||
}
|
||||
SWriteV32(dst, dst_vec);
|
||||
return memory;
|
||||
@@ -745,12 +724,9 @@ DEF_SEM(PMAXSW, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Compute MAX of words
|
||||
auto vec_count = NumVectorElems(lhs_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
auto max = Select(
|
||||
SCmpGt(SExtractV16(lhs_vec, i), SExtractV16(rhs_vec, i)),
|
||||
SExtractV16(lhs_vec, i),
|
||||
SExtractV16(rhs_vec, i));
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto max = Select(SCmpGt(SExtractV16(lhs_vec, i), SExtractV16(rhs_vec, i)),
|
||||
SExtractV16(lhs_vec, i), SExtractV16(rhs_vec, i));
|
||||
dst_vec = SInsertV16(dst_vec, i, max);
|
||||
}
|
||||
SWriteV16(dst, dst_vec);
|
||||
@@ -774,12 +750,9 @@ DEF_SEM(PMAXUB, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Compute MAX of bytes
|
||||
auto vec_count = NumVectorElems(lhs_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
auto max = Select(
|
||||
UCmpGt(UExtractV8(lhs_vec, i), UExtractV8(rhs_vec, i)),
|
||||
UExtractV8(lhs_vec, i),
|
||||
UExtractV8(rhs_vec, i));
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto max = Select(UCmpGt(UExtractV8(lhs_vec, i), UExtractV8(rhs_vec, i)),
|
||||
UExtractV8(lhs_vec, i), UExtractV8(rhs_vec, i));
|
||||
dst_vec = UInsertV8(dst_vec, i, max);
|
||||
}
|
||||
UWriteV8(dst, dst_vec);
|
||||
@@ -803,12 +776,9 @@ DEF_SEM(PMINSW, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Compute MIN of words
|
||||
auto vec_count = NumVectorElems(lhs_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
auto max = Select(
|
||||
SCmpLt(SExtractV16(lhs_vec, i), SExtractV16(rhs_vec, i)),
|
||||
SExtractV16(lhs_vec, i),
|
||||
SExtractV16(rhs_vec, i));
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto max = Select(SCmpLt(SExtractV16(lhs_vec, i), SExtractV16(rhs_vec, i)),
|
||||
SExtractV16(lhs_vec, i), SExtractV16(rhs_vec, i));
|
||||
dst_vec = SInsertV16(dst_vec, i, max);
|
||||
}
|
||||
SWriteV16(dst, dst_vec);
|
||||
@@ -833,12 +803,9 @@ DEF_SEM(PMINUB, D dst, S1 src1, S2 src2) {
|
||||
// Compute MIN of bytes
|
||||
auto vec_count = NumVectorElems(lhs_vec);
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
auto max = Select(
|
||||
UCmpLt(UExtractV8(lhs_vec, i), UExtractV8(rhs_vec, i)),
|
||||
UExtractV8(lhs_vec, i),
|
||||
UExtractV8(rhs_vec, i));
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto max = Select(UCmpLt(UExtractV8(lhs_vec, i), UExtractV8(rhs_vec, i)),
|
||||
UExtractV8(lhs_vec, i), UExtractV8(rhs_vec, i));
|
||||
dst_vec = UInsertV8(dst_vec, i, max);
|
||||
}
|
||||
UWriteV8(dst, dst_vec);
|
||||
@@ -860,10 +827,9 @@ DEF_SEM(PMULHRSW, D dst, S1 src1, S2 src2) {
|
||||
auto rhs_vec = SReadV16(src2);
|
||||
auto dst_vec = SClearV16(SReadV16(dst));
|
||||
auto vec_count = NumVectorElems(lhs_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
auto mul = SMul(Int32(SExtractV16(lhs_vec, i)),
|
||||
Int32(SExtractV16(rhs_vec, i)));
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto mul =
|
||||
SMul(Int32(SExtractV16(lhs_vec, i)), Int32(SExtractV16(rhs_vec, i)));
|
||||
auto temp = SAdd(SShr(mul, decltype(mul)(14)), decltype(mul)(1));
|
||||
temp = SShr(temp, decltype(temp)(1));
|
||||
dst_vec = SInsertV16(dst_vec, i, Int16(temp));
|
||||
@@ -889,10 +855,9 @@ DEF_SEM(PMADDWD, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Multiply and Add Packed Integers
|
||||
auto vec_count = NumVectorElems(lhs_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i += 2) {
|
||||
auto mul1 = SMul(Int32(SExtractV16(lhs_vec, i)),
|
||||
Int32(SExtractV16(rhs_vec, i)));
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i += 2) {
|
||||
auto mul1 =
|
||||
SMul(Int32(SExtractV16(lhs_vec, i)), Int32(SExtractV16(rhs_vec, i)));
|
||||
auto mul2 = SMul(Int32(SExtractV16(lhs_vec, i + 1)),
|
||||
Int32(SExtractV16(rhs_vec, i + 1)));
|
||||
dst_vec = SInsertV32(dst_vec, i / 2, SAdd(mul1, mul2));
|
||||
@@ -918,23 +883,20 @@ DEF_SEM(PMADDUBSW, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Multiply and Add Packed Signed and Unsigned Bytes
|
||||
auto vec_count = NumVectorElems(lhs_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i += 2) {
|
||||
auto mul1 = SMul(Int16(UExtractV8(lhs_vec, i)),
|
||||
Int16(SExtractV8(rhs_vec, i)));
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i += 2) {
|
||||
auto mul1 =
|
||||
SMul(Int16(UExtractV8(lhs_vec, i)), Int16(SExtractV8(rhs_vec, i)));
|
||||
auto mul2 = SMul(Int16(UExtractV8(lhs_vec, i + 1)),
|
||||
Int16(SExtractV8(rhs_vec, i + 1)));
|
||||
auto add_elem = SAdd(mul2, mul1);
|
||||
auto or_elem = SOr(mul2, mul1);
|
||||
auto and_elem = SAnd(mul2, mul1);
|
||||
auto tmp = Select(
|
||||
SCmpLt(SAnd(add_elem, SNot(or_elem)), decltype(add_elem)(0)),
|
||||
decltype(add_elem)(0x7FFF),
|
||||
add_elem);
|
||||
auto value = Select(
|
||||
SCmpLt(SAnd(SNot(add_elem), and_elem), decltype(add_elem)(0)),
|
||||
decltype(add_elem)(0x8000),
|
||||
tmp);
|
||||
auto tmp =
|
||||
Select(SCmpLt(SAnd(add_elem, SNot(or_elem)), decltype(add_elem)(0)),
|
||||
decltype(add_elem)(0x7FFF), add_elem);
|
||||
auto value =
|
||||
Select(SCmpLt(SAnd(SNot(add_elem), and_elem), decltype(add_elem)(0)),
|
||||
decltype(add_elem)(0x8000), tmp);
|
||||
dst_vec = SInsertV16(dst_vec, i / 2, value);
|
||||
}
|
||||
SWriteV16(dst, dst_vec);
|
||||
@@ -955,8 +917,7 @@ DEF_SEM(PABSB, D dst, S1 src1) {
|
||||
auto src_vec = SReadV8(src1);
|
||||
auto dst_vec = SClearV8(SReadV8(dst));
|
||||
auto vec_count = NumVectorElems(src_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto src_entry = SExtractV8(src_vec, i);
|
||||
auto mask = SShr(src_entry, decltype(src_entry)(7));
|
||||
auto abs_value = SSub(SXor(src_entry, mask), mask);
|
||||
@@ -971,8 +932,7 @@ DEF_SEM(PABSW, D dst, S1 src1) {
|
||||
auto src_vec = SReadV16(src1);
|
||||
auto dst_vec = SClearV16(SReadV16(dst));
|
||||
auto vec_count = NumVectorElems(src_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto src_entry = SExtractV16(src_vec, i);
|
||||
auto mask = SShr(src_entry, decltype(src_entry)(15));
|
||||
auto abs_value = SSub(SXor(src_entry, mask), mask);
|
||||
@@ -987,8 +947,7 @@ DEF_SEM(PABSD, D dst, S1 src1) {
|
||||
auto src_vec = SReadV32(src1);
|
||||
auto dst_vec = SClearV32(SReadV32(dst));
|
||||
auto vec_count = NumVectorElems(src_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto src_entry = SExtractV32(src_vec, i);
|
||||
auto mask = SShr(src_entry, decltype(src_entry)(31));
|
||||
auto abs_value = SSub(SXor(src_entry, mask), mask);
|
||||
@@ -1015,6 +974,7 @@ DEF_ISEL(PABSD_XMMdq_XMMdq) = PABSD<V128W, V128>;
|
||||
DEF_ISEL(PABSD_XMMdq_MEMdq) = PABSD<V128W, MV128>;
|
||||
|
||||
namespace {
|
||||
|
||||
// Need a better solution for handling PACKSS;
|
||||
// Soln : Sign extension and compare
|
||||
template <typename D, typename S1, typename S2>
|
||||
@@ -1025,23 +985,19 @@ DEF_SEM(PACKSSWB, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Convert signed word to saturated signed byte
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV16(src1_vec, i);
|
||||
auto v2 = SExtractV8(dst_vec, i);
|
||||
auto value = Select(SCmpGt(v1, SExt(Maximize(v2))),
|
||||
Maximize(v2),
|
||||
Trunc(v1));
|
||||
auto value =
|
||||
Select(SCmpGt(v1, SExt(Maximize(v2))), Maximize(v2), Trunc(v1));
|
||||
value = Select(SCmpLt(v1, SExt(Minimize(v2))), Minimize(v2), value);
|
||||
dst_vec = SInsertV8(dst_vec, i, value);
|
||||
}
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < NumVectorElems(src2_vec); i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < NumVectorElems(src2_vec); i++) {
|
||||
auto v1 = SExtractV16(src2_vec, i);
|
||||
auto v2 = SExtractV8(dst_vec, i);
|
||||
auto value = Select(SCmpGt(v1, SExt(Maximize(v2))),
|
||||
Maximize(v2),
|
||||
Trunc(v1));
|
||||
auto value =
|
||||
Select(SCmpGt(v1, SExt(Maximize(v2))), Maximize(v2), Trunc(v1));
|
||||
value = Select(SCmpLt(v1, SExt(Minimize(v2))), Minimize(v2), value);
|
||||
dst_vec = SInsertV8(dst_vec, i + vec_count, value);
|
||||
}
|
||||
@@ -1061,25 +1017,22 @@ DEF_SEM(PACKSSDW, D dst, S1 src1, S2 src2) {
|
||||
auto src1_vec = SReadV32(src1);
|
||||
auto src2_vec = SReadV32(src2);
|
||||
auto dst_vec = SClearV16(SReadV16(dst));
|
||||
|
||||
// Convert signed word to saturated signed byte
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV32(src1_vec, i);
|
||||
auto v2 = SExtractV16(dst_vec, i);
|
||||
auto value = Select(SCmpGt(v1, SExt(Maximize(v2))),
|
||||
Maximize(v2),
|
||||
Trunc(v1));
|
||||
auto value =
|
||||
Select(SCmpGt(v1, SExt(Maximize(v2))), Maximize(v2), Trunc(v1));
|
||||
value = Select(SCmpLt(v1, SExt(Minimize(v2))), Minimize(v2), value);
|
||||
dst_vec = SInsertV16(dst_vec, i, value);
|
||||
}
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < NumVectorElems(src2_vec); i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < NumVectorElems(src2_vec); i++) {
|
||||
auto v1 = SExtractV32(src2_vec, i);
|
||||
auto v2 = SExtractV16(dst_vec, i);
|
||||
auto value = Select(SCmpGt(v1, SExt(Maximize(v2))),
|
||||
Maximize(v2),
|
||||
Trunc(v1));
|
||||
auto value =
|
||||
Select(SCmpGt(v1, SExt(Maximize(v2))), Maximize(v2), Trunc(v1));
|
||||
value = Select(SCmpLt(v1, SExt(Minimize(v2))), Minimize(v2), value);
|
||||
dst_vec = SInsertV16(dst_vec, i + vec_count, value);
|
||||
}
|
||||
@@ -1196,11 +1149,10 @@ DEF_SEM(PALIGNR_64, V64W dst, V64 src1, S2 src2, I8 imm1) {
|
||||
auto zero_shift = UCmpEq(shift, 0_u64);
|
||||
auto max_shift = UCmpEq(shift, 64_u64);
|
||||
|
||||
auto src1_elem_high = Select(
|
||||
zero_shift, 0_u64, UShl(src1_elem, USub(64_u64, shift)));
|
||||
auto src1_elem_high =
|
||||
Select(zero_shift, 0_u64, UShl(src1_elem, USub(64_u64, shift)));
|
||||
|
||||
auto src2_elem_low = Select(
|
||||
max_shift, src1_elem, UShr(src2_elem, shift));
|
||||
auto src2_elem_low = Select(max_shift, src1_elem, UShr(src2_elem, shift));
|
||||
|
||||
auto combined = UOr(src1_elem_high, src2_elem_low);
|
||||
UWriteV64(dst, UInsertV64(dst_vec, 0, combined));
|
||||
@@ -1220,10 +1172,9 @@ DEF_SEM(PALIGNR_128, V128W dst, V128 src1, S2 src2, I8 imm1) {
|
||||
auto zero_shift = UCmpEq(shift, 0_u128);
|
||||
auto max_shift = UCmpEq(shift, 128_u128);
|
||||
|
||||
auto src1_elem_high = Select(
|
||||
zero_shift, 0_u128, UShl(src1_elem, USub(128_u128, shift)));
|
||||
auto src2_elem_low = Select(
|
||||
max_shift, src1_elem, UShr(src2_elem, shift));
|
||||
auto src1_elem_high =
|
||||
Select(zero_shift, 0_u128, UShl(src1_elem, USub(128_u128, shift)));
|
||||
auto src2_elem_low = Select(max_shift, src1_elem, UShr(src2_elem, shift));
|
||||
|
||||
auto combined = UOr(src1_elem_high, src2_elem_low);
|
||||
UWriteV128(dst, UInsertV128(dst_vec, 0, combined));
|
||||
@@ -1246,11 +1197,9 @@ DEF_SEM(PSRLW, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = UClearV16(UReadV16(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = UExtractV16(src1_vec, i);
|
||||
auto temp = Select(
|
||||
UCmpGt(count, static_cast<decltype(count)>(15)),
|
||||
auto temp = Select(UCmpGt(count, static_cast<decltype(count)>(15)),
|
||||
static_cast<decltype(v1)>(0),
|
||||
UShr(v1, static_cast<decltype(v1)>(count)));
|
||||
dst_vec = UInsertV16(dst_vec, i, temp);
|
||||
@@ -1267,11 +1216,9 @@ DEF_SEM(PSRLW_V, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = UClearV16(UReadV16(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = UExtractV16(src1_vec, i);
|
||||
auto temp = Select(
|
||||
UCmpGt(count, static_cast<decltype(count)>(15)),
|
||||
auto temp = Select(UCmpGt(count, static_cast<decltype(count)>(15)),
|
||||
static_cast<decltype(v1)>(0),
|
||||
UShr(v1, static_cast<decltype(v1)>(count)));
|
||||
dst_vec = UInsertV16(dst_vec, i, temp);
|
||||
@@ -1287,11 +1234,9 @@ DEF_SEM(PSRLD, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = UClearV32(UReadV32(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = UExtractV32(src1_vec, i);
|
||||
auto temp = Select(
|
||||
UCmpGt(count, static_cast<decltype(count)>(31)),
|
||||
auto temp = Select(UCmpGt(count, static_cast<decltype(count)>(31)),
|
||||
static_cast<decltype(v1)>(0),
|
||||
UShr(v1, static_cast<decltype(v1)>(count)));
|
||||
dst_vec = UInsertV32(dst_vec, i, temp);
|
||||
@@ -1308,11 +1253,9 @@ DEF_SEM(PSRLD_V, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = UClearV32(UReadV32(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = UExtractV32(src1_vec, i);
|
||||
auto temp = Select(
|
||||
UCmpGt(count, static_cast<decltype(count)>(31)),
|
||||
auto temp = Select(UCmpGt(count, static_cast<decltype(count)>(31)),
|
||||
static_cast<decltype(v1)>(0),
|
||||
UShr(v1, static_cast<decltype(v1)>(count)));
|
||||
dst_vec = UInsertV32(dst_vec, i, temp);
|
||||
@@ -1328,11 +1271,9 @@ DEF_SEM(PSRLQ, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = UClearV64(UReadV64(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = UExtractV64(src1_vec, i);
|
||||
auto temp = Select(
|
||||
UCmpGt(count, static_cast<decltype(count)>(63)),
|
||||
auto temp = Select(UCmpGt(count, static_cast<decltype(count)>(63)),
|
||||
static_cast<decltype(v1)>(0),
|
||||
UShr(v1, static_cast<decltype(v1)>(count)));
|
||||
dst_vec = UInsertV64(dst_vec, i, temp);
|
||||
@@ -1349,11 +1290,9 @@ DEF_SEM(PSRLQ_V, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = UClearV64(UReadV64(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = UExtractV64(src1_vec, i);
|
||||
auto temp = Select(
|
||||
UCmpGt(count, static_cast<decltype(count)>(63)),
|
||||
auto temp = Select(UCmpGt(count, static_cast<decltype(count)>(63)),
|
||||
static_cast<decltype(v1)>(0),
|
||||
UShr(v1, static_cast<decltype(v1)>(count)));
|
||||
dst_vec = UInsertV64(dst_vec, i, temp);
|
||||
@@ -1369,15 +1308,12 @@ DEF_SEM(PSRAW, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV16(SReadV16(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV16(src1_vec, i);
|
||||
count = Select(
|
||||
UCmpGt(count, static_cast<decltype(count)>(15)),
|
||||
static_cast<decltype(count)>(16),
|
||||
count);
|
||||
dst_vec = SInsertV16(
|
||||
dst_vec, i, SShr(v1, static_cast<decltype(v1)>(count)));
|
||||
count = Select(UCmpGt(count, static_cast<decltype(count)>(15)),
|
||||
static_cast<decltype(count)>(16), count);
|
||||
dst_vec =
|
||||
SInsertV16(dst_vec, i, SShr(v1, static_cast<decltype(v1)>(count)));
|
||||
}
|
||||
SWriteV16(dst, dst_vec);
|
||||
return memory;
|
||||
@@ -1391,15 +1327,12 @@ DEF_SEM(PSRAW_V, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV16(SReadV16(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV16(src1_vec, i);
|
||||
count = Select(
|
||||
UCmpGt(count, static_cast<decltype(count)>(15)),
|
||||
static_cast<decltype(count)>(16),
|
||||
count);
|
||||
dst_vec = SInsertV16(
|
||||
dst_vec, i, SShr(v1, static_cast<decltype(v1)>(count)));
|
||||
count = Select(UCmpGt(count, static_cast<decltype(count)>(15)),
|
||||
static_cast<decltype(count)>(16), count);
|
||||
dst_vec =
|
||||
SInsertV16(dst_vec, i, SShr(v1, static_cast<decltype(v1)>(count)));
|
||||
}
|
||||
SWriteV16(dst, dst_vec);
|
||||
return memory;
|
||||
@@ -1412,15 +1345,12 @@ DEF_SEM(PSRAD, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV32(SReadV32(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV32(src1_vec, i);
|
||||
count = Select(
|
||||
UCmpGt(count, static_cast<decltype(count)>(31)),
|
||||
static_cast<decltype(count)>(32),
|
||||
count);
|
||||
dst_vec = SInsertV32(
|
||||
dst_vec, i, SShr(v1, static_cast<decltype(v1)>(count)));
|
||||
count = Select(UCmpGt(count, static_cast<decltype(count)>(31)),
|
||||
static_cast<decltype(count)>(32), count);
|
||||
dst_vec =
|
||||
SInsertV32(dst_vec, i, SShr(v1, static_cast<decltype(v1)>(count)));
|
||||
}
|
||||
SWriteV32(dst, dst_vec);
|
||||
return memory;
|
||||
@@ -1434,15 +1364,12 @@ DEF_SEM(PSRAD_V, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV32(SReadV32(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV32(src1_vec, i);
|
||||
count = Select(
|
||||
UCmpGt(count, static_cast<decltype(count)>(31)),
|
||||
static_cast<decltype(count)>(32),
|
||||
count);
|
||||
dst_vec = SInsertV32(
|
||||
dst_vec, i, SShr(v1, static_cast<decltype(v1)>(count)));
|
||||
count = Select(UCmpGt(count, static_cast<decltype(count)>(31)),
|
||||
static_cast<decltype(count)>(32), count);
|
||||
dst_vec =
|
||||
SInsertV32(dst_vec, i, SShr(v1, static_cast<decltype(v1)>(count)));
|
||||
}
|
||||
SWriteV32(dst, dst_vec);
|
||||
return memory;
|
||||
@@ -1515,12 +1442,9 @@ DEF_SEM(PSLLW, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV16(SReadV16(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV16(src1_vec, i);
|
||||
auto temp = Select(
|
||||
UCmpGt(count, static_cast<decltype(count)>(15)),
|
||||
0_s16,
|
||||
auto temp = Select(UCmpGt(count, static_cast<decltype(count)>(15)), 0_s16,
|
||||
SShl(v1, static_cast<int16_t>(count)));
|
||||
dst_vec = SInsertV16(dst_vec, i, temp);
|
||||
}
|
||||
@@ -1536,12 +1460,9 @@ DEF_SEM(PSLLW_V, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV16(SReadV16(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV16(src1_vec, i);
|
||||
auto temp = Select(
|
||||
UCmpGt(count, 15_u64),
|
||||
0_s16,
|
||||
auto temp = Select(UCmpGt(count, 15_u64), 0_s16,
|
||||
SShl(v1, static_cast<int16_t>(count)));
|
||||
dst_vec = SInsertV16(dst_vec, i, temp);
|
||||
}
|
||||
@@ -1556,12 +1477,9 @@ DEF_SEM(PSLLD, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV32(SReadV32(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV32(src1_vec, i);
|
||||
auto temp = Select(
|
||||
UCmpGt(count, static_cast<decltype(count)>(31)),
|
||||
0_s32,
|
||||
auto temp = Select(UCmpGt(count, static_cast<decltype(count)>(31)), 0_s32,
|
||||
SShl(v1, static_cast<int32_t>(count)));
|
||||
dst_vec = SInsertV32(dst_vec, i, temp);
|
||||
}
|
||||
@@ -1577,12 +1495,9 @@ DEF_SEM(PSLLD_V, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV32(SReadV32(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV32(src1_vec, i);
|
||||
auto temp = Select(
|
||||
UCmpGt(count, 31_u64),
|
||||
0_s32,
|
||||
auto temp = Select(UCmpGt(count, 31_u64), 0_s32,
|
||||
SShl(v1, static_cast<int32_t>(count)));
|
||||
dst_vec = SInsertV32(dst_vec, i, temp);
|
||||
}
|
||||
@@ -1597,12 +1512,9 @@ DEF_SEM(PSLLQ, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV64(SReadV64(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV64(src1_vec, i);
|
||||
auto temp = Select(
|
||||
UCmpGt(count, static_cast<decltype(count)>(63)),
|
||||
0_s64,
|
||||
auto temp = Select(UCmpGt(count, static_cast<decltype(count)>(63)), 0_s64,
|
||||
SShl(v1, static_cast<int64_t>(count)));
|
||||
dst_vec = SInsertV64(dst_vec, i, temp);
|
||||
}
|
||||
@@ -1618,12 +1530,9 @@ DEF_SEM(PSLLQ_V, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV64(SReadV64(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV64(src1_vec, i);
|
||||
auto temp = Select(
|
||||
UCmpGt(count, 63_u64),
|
||||
0_s64,
|
||||
auto temp = Select(UCmpGt(count, 63_u64), 0_s64,
|
||||
SShl(v1, static_cast<int64_t>(count)));
|
||||
dst_vec = SInsertV64(dst_vec, i, temp);
|
||||
}
|
||||
@@ -1684,8 +1593,7 @@ DEF_SEM(PSIGNB, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV8(SReadV8(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV8(src1_vec, i);
|
||||
auto v2 = SExtractV8(src2_vec, i);
|
||||
auto is_neg = SignFlag(v2);
|
||||
@@ -1704,8 +1612,7 @@ DEF_SEM(PSIGNW, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV16(SReadV16(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV16(src1_vec, i);
|
||||
auto v2 = SExtractV16(src2_vec, i);
|
||||
auto is_neg = SignFlag(v2);
|
||||
@@ -1724,8 +1631,7 @@ DEF_SEM(PSIGND, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV32(SReadV32(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV32(src1_vec, i);
|
||||
auto v2 = SExtractV32(src2_vec, i);
|
||||
auto is_neg = SignFlag(v2);
|
||||
@@ -1763,9 +1669,8 @@ DEF_SEM(PSHUFB, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = UClearV8(UReadV8(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
uint8_t mask = vec_count - 1;
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
uint8_t mask = static_cast<uint8_t>(vec_count - 1u);
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
uint8_t v1 = UExtractV8(src2_vec, i);
|
||||
uint8_t index = UAnd(v1, mask);
|
||||
uint8_t v2 = UExtractV8(src1_vec, index);
|
||||
@@ -1783,8 +1688,7 @@ DEF_SEM(PSHUFW, D dst, S1 src1, I8 src2) {
|
||||
auto order = Read(src2);
|
||||
|
||||
auto vec_count = NumVectorElems(dst_vec);
|
||||
_Pragma("unroll")
|
||||
for (uint8_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (uint8_t i = 0; i < vec_count; i++) {
|
||||
auto mask = UAnd(UShr(order, i), 3_u8);
|
||||
auto v1 = UExtractV16(src_vec, mask);
|
||||
dst_vec = UInsertV16(dst_vec, i, v1);
|
||||
@@ -1812,11 +1716,9 @@ DEF_SEM(PSADBW, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = UClearV64(UReadV64(dst));
|
||||
auto vec_count = NumVectorElems(dst_vec);
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0, k = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0, k = 0; i < vec_count; i++) {
|
||||
uint16_t sum = 0;
|
||||
_Pragma("unroll")
|
||||
for (size_t j = 0; j < 8UL; ++j, ++k) {
|
||||
_Pragma("unroll") for (size_t j = 0; j < 8UL; ++j, ++k) {
|
||||
uint8_t v1 = UExtractV8(src1_vec, k);
|
||||
uint8_t v2 = UExtractV8(src2_vec, k);
|
||||
uint8_t abs_diff = Select(UCmpGte(v1, v2), USub(v1, v2), USub(v2, v1));
|
||||
@@ -1848,8 +1750,7 @@ DEF_SEM(PMULUDQ, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = UClearV64(UReadV64(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count/2; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count / 2; i++) {
|
||||
auto v1 = ZExt(UExtractV32(src1_vec, i * 2));
|
||||
auto v2 = ZExt(UExtractV32(src2_vec, i * 2));
|
||||
auto mul = UMul(v1, v2);
|
||||
@@ -1866,8 +1767,7 @@ DEF_SEM(PMULLW, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV16(SReadV16(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV16(src1_vec, i);
|
||||
auto v2 = SExtractV16(src2_vec, i);
|
||||
auto mul = SMul(SExt(v1), SExt(v2));
|
||||
@@ -1884,8 +1784,7 @@ DEF_SEM(PMULHW, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = SClearV16(SReadV16(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = SExtractV16(src1_vec, i);
|
||||
auto v2 = SExtractV16(src2_vec, i);
|
||||
auto mul = SMul(SExt(v1), SExt(v2));
|
||||
@@ -1902,8 +1801,7 @@ DEF_SEM(PMULHUW, D dst, S1 src1, S2 src2) {
|
||||
auto dst_vec = UClearV16(UReadV16(dst));
|
||||
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = UExtractV16(src1_vec, i);
|
||||
auto v2 = UExtractV16(src2_vec, i);
|
||||
auto mul = UMul(ZExt(v1), ZExt(v2));
|
||||
@@ -1941,10 +1839,10 @@ template <typename D, typename S>
|
||||
DEF_SEM(PMOVMSKB, D dst, S src2) {
|
||||
auto src_vec = UReadV8(src2);
|
||||
uint32_t r32 = 0U;
|
||||
|
||||
// reset all bits to zero
|
||||
auto vec_count = NumVectorElems(src_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = vec_count; i-- > 0; ) {
|
||||
_Pragma("unroll") for (size_t i = vec_count; i-- > 0;) {
|
||||
auto v1 = UExtractV8(src_vec, i);
|
||||
r32 = UOr(UShl(r32, 1_u32), static_cast<uint32_t>(UShr(v1, 7_u8)));
|
||||
}
|
||||
@@ -1981,8 +1879,7 @@ DEF_SEM(DoMASKMOVQ_MMXq_MMXq, V64 src1, V64 src2) {
|
||||
auto src1_vec = UReadV8(src1);
|
||||
auto src2_vec = UReadV8(src2);
|
||||
auto vec_count = NumVectorElems(src1_vec);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < vec_count; i++) {
|
||||
uint8_t src_byte = UExtractV8(src1_vec, i);
|
||||
uint8_t mask_byte = UExtractV8(src2_vec, i);
|
||||
uint8_t mem_byte = UExtractV8(dst_vec, i);
|
||||
|
||||
@@ -71,6 +71,7 @@ DEF_SEM(DoPOPFD) {
|
||||
state.aflag.zf = f.zf;
|
||||
|
||||
state.rflag.id = f.id;
|
||||
|
||||
// state.rflag.ac = f.ac;
|
||||
// state.rflag.tf = f.tf;
|
||||
// state.rflag.nt = f.nt;
|
||||
@@ -91,6 +92,7 @@ DEF_SEM(DoPOPFQ) {
|
||||
state.aflag.zf = f.zf;
|
||||
|
||||
state.rflag.id = f.id;
|
||||
|
||||
// state.rflag.ac = f.ac;
|
||||
// state.rflag.tf = f.tf;
|
||||
// state.rflag.nt = f.nt;
|
||||
@@ -145,8 +147,8 @@ DEF_SEM(POP_ES, R16W dst) {
|
||||
addr_t stack_ptr = Read(REG_XSP);
|
||||
Write(dst, TruncTo<uint16_t>(Read(ReadPtr<T>(stack_ptr))));
|
||||
Write(REG_XSP, UAdd(stack_ptr, addr_size));
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86SetSegmentES);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86SetSegmentES);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -155,8 +157,8 @@ DEF_SEM(POP_SS, R16W dst) {
|
||||
addr_t stack_ptr = Read(REG_XSP);
|
||||
Write(dst, TruncTo<uint16_t>(Read(ReadPtr<T>(stack_ptr))));
|
||||
Write(REG_XSP, UAdd(stack_ptr, addr_size));
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86SetSegmentSS);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86SetSegmentSS);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -165,8 +167,8 @@ DEF_SEM(POP_DS, R16W dst) {
|
||||
addr_t stack_ptr = Read(REG_XSP);
|
||||
Write(dst, TruncTo<uint16_t>(Read(ReadPtr<T>(stack_ptr))));
|
||||
Write(REG_XSP, UAdd(stack_ptr, addr_size));
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86SetSegmentDS);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86SetSegmentDS);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -175,8 +177,8 @@ DEF_SEM(POP_FS, R16W dst) {
|
||||
addr_t stack_ptr = Read(REG_XSP);
|
||||
Write(dst, TruncTo<uint16_t>(Read(ReadPtr<T>(stack_ptr))));
|
||||
Write(REG_XSP, UAdd(stack_ptr, addr_size));
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86SetSegmentFS);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86SetSegmentFS);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -185,8 +187,8 @@ DEF_SEM(POP_GS, R16W dst) {
|
||||
addr_t stack_ptr = Read(REG_XSP);
|
||||
Write(dst, TruncTo<uint16_t>(Read(ReadPtr<T>(stack_ptr))));
|
||||
Write(REG_XSP, UAdd(stack_ptr, addr_size));
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86SetSegmentGS);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86SetSegmentGS);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -20,17 +20,22 @@ namespace {
|
||||
|
||||
static void SerializeFlags(State &state) {
|
||||
state.rflag.cf = state.aflag.cf;
|
||||
|
||||
//state.rflag.must_be_1 = 1;
|
||||
state.rflag.pf = state.aflag.pf;
|
||||
|
||||
//state.rflag.must_be_0a = 0;
|
||||
state.rflag.af = state.aflag.af;
|
||||
|
||||
//state.rflag.must_be_0b = 0;
|
||||
state.rflag.zf = state.aflag.zf;
|
||||
state.rflag.sf = state.aflag.sf;
|
||||
|
||||
//state.rflag.tf = 0; // Trap flag (not single-stepping).
|
||||
//state.rflag._if = 1; // Interrupts are enabled (assumes user mode).
|
||||
state.rflag.df = state.aflag.df;
|
||||
state.rflag.of = state.aflag.of;
|
||||
|
||||
//state.rflag.iopl = 0; // In user-mode. TODO(pag): Configurable?
|
||||
//state.rflag.nt = 0; // Not running in a nested task (interrupted interrupt).
|
||||
//state.rflag.must_be_0c = 0;
|
||||
|
||||
@@ -30,9 +30,8 @@ DEF_SEM(ROL, D dst, S1 src1, S2 src2) {
|
||||
auto masked_count = UAnd(count, count_mask);
|
||||
auto temp_count = URem(masked_count, op_size);
|
||||
if (temp_count) {
|
||||
auto new_val = UOr(
|
||||
UShl(val, temp_count),
|
||||
UShr(val, USub(op_size, temp_count)));
|
||||
auto new_val =
|
||||
UOr(UShl(val, temp_count), UShr(val, USub(op_size, temp_count)));
|
||||
WriteZExt(dst, new_val);
|
||||
Write(FLAG_CF, UCmpEq(UAnd(new_val, one), one));
|
||||
if (1 == temp_count) {
|
||||
@@ -59,12 +58,12 @@ DEF_SEM(ROR, D dst, S1 src1, S2 src2) {
|
||||
auto masked_count = UAnd(count, count_mask);
|
||||
auto temp_count = URem(masked_count, op_size);
|
||||
if (temp_count) {
|
||||
auto new_val = UOr(
|
||||
UShr(val, temp_count),
|
||||
UShl(val, USub(op_size, temp_count)));
|
||||
auto new_val =
|
||||
UOr(UShr(val, temp_count), UShl(val, USub(op_size, temp_count)));
|
||||
WriteZExt(dst, new_val);
|
||||
Write(FLAG_CF, SignFlag(new_val));
|
||||
Write(FLAG_OF, BXor(FLAG_CF, SignFlag(UShl(new_val, one))));
|
||||
|
||||
// OF undefined for `1 == temp_count`.
|
||||
} else {
|
||||
WriteZExt(dst, val);
|
||||
@@ -82,9 +81,8 @@ DEF_SEM(RORX, D dst, S1 src1, S2 src2) {
|
||||
auto count_mask = Select(UCmpEq(op_size, 64), long_mask, short_mask);
|
||||
auto masked_count = UAnd(count, count_mask);
|
||||
auto temp_count = URem(masked_count, op_size);
|
||||
auto new_val = UOr(
|
||||
UShr(val, temp_count),
|
||||
UShl(val, USub(op_size, temp_count)));
|
||||
auto new_val =
|
||||
UOr(UShr(val, temp_count), UShl(val, USub(op_size, temp_count)));
|
||||
WriteZExt(dst, new_val);
|
||||
return memory;
|
||||
}
|
||||
@@ -134,10 +132,8 @@ DEF_SEM(RCL, D dst, S1 src1, S2 src2) {
|
||||
auto short_mask = Literal<S1>(0x1F);
|
||||
auto op_size = BitSizeOf(src1);
|
||||
auto count_mask = Select(UCmpEq(op_size, 64), long_mask, short_mask);
|
||||
auto count_mod = Select(
|
||||
UCmpLt(op_size, 32),
|
||||
UAdd(op_size, one),
|
||||
UAdd(count_mask, one));
|
||||
auto count_mod =
|
||||
Select(UCmpLt(op_size, 32), UAdd(op_size, one), UAdd(count_mask, one));
|
||||
|
||||
auto masked_count = UAnd(count, count_mask);
|
||||
auto temp_count = URem(masked_count, count_mod);
|
||||
@@ -145,13 +141,13 @@ DEF_SEM(RCL, D dst, S1 src1, S2 src2) {
|
||||
|
||||
if (temp_count) {
|
||||
auto right = UShr(val, USub(op_size, temp_count));
|
||||
auto new_val = UOr(UOr(
|
||||
UShl(val, temp_count),
|
||||
UShl(carry, USub(temp_count, one))),
|
||||
auto new_val =
|
||||
UOr(UOr(UShl(val, temp_count), UShl(carry, USub(temp_count, one))),
|
||||
UShr(right, one));
|
||||
WriteZExt(dst, new_val);
|
||||
Write(FLAG_CF, SignFlag(UShl(val, USub(temp_count, one))));
|
||||
Write(FLAG_OF, BXor(FLAG_CF, SignFlag(new_val)));
|
||||
|
||||
// OF undefined for `1 == temp_count`.
|
||||
} else {
|
||||
WriteZExt(dst, val);
|
||||
@@ -169,10 +165,8 @@ DEF_SEM(RCR, D dst, S1 src1, S2 src2) {
|
||||
auto short_mask = Literal<S1>(0x1F);
|
||||
auto op_size = BitSizeOf(src1);
|
||||
auto count_mask = Select(UCmpEq(op_size, 64), long_mask, short_mask);
|
||||
auto count_mod = Select(
|
||||
UCmpLt(op_size, 32),
|
||||
UAdd(op_size, one),
|
||||
UAdd(count_mask, one));
|
||||
auto count_mod =
|
||||
Select(UCmpLt(op_size, 32), UAdd(op_size, one), UAdd(count_mask, one));
|
||||
|
||||
auto masked_count = UAnd(count, count_mask);
|
||||
auto temp_count = URem(masked_count, count_mod);
|
||||
@@ -181,13 +175,13 @@ DEF_SEM(RCR, D dst, S1 src1, S2 src2) {
|
||||
if (temp_count) {
|
||||
auto left = UShr(val, USub(temp_count, one));
|
||||
auto right = UShl(val, USub(op_size, temp_count));
|
||||
auto new_val = UOr(UOr(
|
||||
UShr(left, one),
|
||||
UShl(carry, USub(op_size, temp_count))),
|
||||
auto new_val =
|
||||
UOr(UOr(UShr(left, one), UShl(carry, USub(op_size, temp_count))),
|
||||
UShl(right, one));
|
||||
WriteZExt(dst, new_val);
|
||||
Write(FLAG_CF, UCmpNeq(UAnd(left, one), zero));
|
||||
Write(FLAG_OF, BXor(SignFlag(UShl(new_val, one)), SignFlag(new_val)));
|
||||
|
||||
// OF undefined for `1 == temp_count`.
|
||||
} else {
|
||||
WriteZExt(dst, val);
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
namespace {
|
||||
|
||||
// Note: The taken branch is the transaction failed fallback path.
|
||||
DEF_SEM(XBEGIN, R8W cond, PC taken, PC not_taken, IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
DEF_SEM(XBEGIN, R8W cond, PC taken, PC not_taken,
|
||||
IF_32BIT_ELSE(R32W, R64W) pc_dst) {
|
||||
Write(cond, true);
|
||||
Write(pc_dst, Read(taken));
|
||||
WriteZExt(REG_XAX, static_cast<addr_t>(8));
|
||||
|
||||
@@ -114,4 +114,3 @@ DEF_ISEL(XADD_MEMb_GPR8) = XADD<M8W, M8, R8W, R8>;
|
||||
DEF_ISEL(XADD_GPR8_GPR8) = XADD<R8W, R8, R8W, R8>;
|
||||
DEF_ISEL_MnW_Mn_RnW_Rn(XADD_MEMv_GPRv, XADD);
|
||||
DEF_ISEL_RnW_Rn_RnW_Rn(XADD_GPRv_GPRv, XADD);
|
||||
|
||||
|
||||
@@ -262,6 +262,7 @@ DEF_SEM(SHRD, D dst, S1 src1, S2 src2, S3 src3) {
|
||||
Write(FLAG_ZF, ZeroFlag(res));
|
||||
Write(FLAG_SF, SignFlag(res));
|
||||
Write(FLAG_OF, BXor(SignFlag(val1), FLAG_SF));
|
||||
|
||||
// OF undefined for `1 == temp_count`.
|
||||
return memory;
|
||||
}
|
||||
@@ -298,6 +299,7 @@ DEF_SEM(SHLD, D dst, S1 src1, S2 src2, S3 src3) {
|
||||
|
||||
} else if (UCmpLt(op_size, masked_shift)) {
|
||||
ClearArithFlags();
|
||||
|
||||
// `dst` is undefined; leave as-is, except w.r.t
|
||||
// zero-extension.
|
||||
//
|
||||
@@ -320,6 +322,7 @@ DEF_SEM(SHLD, D dst, S1 src1, S2 src2, S3 src3) {
|
||||
Write(FLAG_ZF, ZeroFlag(res));
|
||||
Write(FLAG_SF, SignFlag(res));
|
||||
Write(FLAG_OF, BXor(SignFlag(val1), FLAG_SF));
|
||||
|
||||
// OF undefined for `1 == temp_count`.
|
||||
return memory;
|
||||
}
|
||||
@@ -338,8 +341,7 @@ DEF_SEM(PSLLDQ, D dst, V128 src1, I8 src2) {
|
||||
uint8v16_t src1_vec = UReadV8(src1);
|
||||
uint8v16_t dst_vec = {};
|
||||
size_t shift_amount = std::min<size_t>(ZExtTo<size_t>(Read(src2)), 16);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < 16; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < 16; ++i) {
|
||||
if (i < (16 - shift_amount)) {
|
||||
dst_vec = UInsertV8(dst_vec, i + shift_amount, UExtractV8(src1_vec, i));
|
||||
}
|
||||
@@ -355,8 +357,7 @@ DEF_SEM(VPSLLDQ, D dst, V256 src1, I8 src2) {
|
||||
uint8v32_t dst_vec = {};
|
||||
size_t shift_amount = std::min<size_t>(ZExtTo<size_t>(Read(src2)), 16);
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0, j = 16; i < 16; ++i, ++j) {
|
||||
_Pragma("unroll") for (size_t i = 0, j = 16; i < 16; ++i, ++j) {
|
||||
if (i < (16 - shift_amount)) {
|
||||
dst_vec = UInsertV8(dst_vec, i + shift_amount, UExtractV8(src1_vec, i));
|
||||
dst_vec = UInsertV8(dst_vec, j + shift_amount, UExtractV8(src1_vec, j));
|
||||
|
||||
+128
-167
@@ -58,70 +58,39 @@ ALWAYS_INLINE static bool CompareFloats(FloatCompareOperator op, T v1, T v2) {
|
||||
auto is_unordered = __builtin_isunordered(v1, v2);
|
||||
auto is_ordered = !is_unordered;
|
||||
switch (op) {
|
||||
case kEqOrderedQuiet:
|
||||
return !__builtin_islessgreater(v1, v2) && is_ordered;
|
||||
case kLtOrderedSignal:
|
||||
return v1 < v2 && is_ordered;
|
||||
case kLeOrderedSignal:
|
||||
return v1 <= v2 && is_ordered;
|
||||
case kUnorderedQuiet:
|
||||
return is_unordered;
|
||||
case kEqOrderedQuiet: return !__builtin_islessgreater(v1, v2) && is_ordered;
|
||||
case kLtOrderedSignal: return v1 < v2 && is_ordered;
|
||||
case kLeOrderedSignal: return v1 <= v2 && is_ordered;
|
||||
case kUnorderedQuiet: return is_unordered;
|
||||
case kNeUnorderedQuiet:
|
||||
return __builtin_islessgreater(v1, v2) || is_unordered;
|
||||
case kNltUnorderedSignal:
|
||||
return !(v1 < v2) || is_unordered;
|
||||
case kNleUnorderedSignal:
|
||||
return !(v1 <= v2) || is_unordered;
|
||||
case kOrderedQuiet:
|
||||
return is_ordered;
|
||||
case kEqUnorderedQuiet:
|
||||
return !__builtin_islessgreater(v1, v2);
|
||||
case kNgeUnorderedSignal:
|
||||
return !(v1 >= v2) || is_unordered;
|
||||
case kNgtUnorderedSignal:
|
||||
return !(v1 > v2) || is_unordered;
|
||||
case kFalseOrderedQuiet:
|
||||
return false;
|
||||
case kNeOrderedQuiet:
|
||||
return __builtin_islessgreater(v1, v2);
|
||||
case kGeOrderedSignal:
|
||||
return v1 >= v2 && is_ordered;
|
||||
case kGtOrderedSignal:
|
||||
return v1 > v2 && is_ordered;
|
||||
case kTrueUnorderedQuiet:
|
||||
return true;
|
||||
case kEqOrderedSignal:
|
||||
return v1 == v2 && is_ordered;
|
||||
case kLtOrderedQuiet:
|
||||
return __builtin_isless(v1, v2);
|
||||
case kLeOrderedQuiet:
|
||||
return __builtin_islessequal(v1, v2);
|
||||
case kUnorderedSignal:
|
||||
return is_unordered;
|
||||
case kNeUnorderedSignal:
|
||||
return v1 != v2 || is_unordered;
|
||||
case kNltUnorderedQuiet:
|
||||
return !__builtin_isless(v1, v2);
|
||||
case kNleUnorderedQuiet:
|
||||
return !__builtin_islessequal(v1, v2);
|
||||
case kOrderedSignal:
|
||||
return is_ordered;
|
||||
case kEqUnorderedSignal:
|
||||
return v1 == v2 || is_unordered;
|
||||
case kNgeUnorderedQuiet:
|
||||
return !__builtin_isgreaterequal(v1, v2);
|
||||
case kNgtUnorderedQuiet:
|
||||
return !__builtin_isgreater(v1, v2);
|
||||
case kFalseOrderedSignal:
|
||||
return false;
|
||||
case kNeOrderedSignal:
|
||||
return !(v1 == v2) && is_ordered;
|
||||
case kGeOrderedQuiet:
|
||||
return __builtin_isgreaterequal(v1, v2);
|
||||
case kGtOrderedQuiet:
|
||||
return __builtin_isgreater(v1, v2);
|
||||
case kTrueUnorderedSignal:
|
||||
return true;
|
||||
case kNltUnorderedSignal: return !(v1 < v2) || is_unordered;
|
||||
case kNleUnorderedSignal: return !(v1 <= v2) || is_unordered;
|
||||
case kOrderedQuiet: return is_ordered;
|
||||
case kEqUnorderedQuiet: return !__builtin_islessgreater(v1, v2);
|
||||
case kNgeUnorderedSignal: return !(v1 >= v2) || is_unordered;
|
||||
case kNgtUnorderedSignal: return !(v1 > v2) || is_unordered;
|
||||
case kFalseOrderedQuiet: return false;
|
||||
case kNeOrderedQuiet: return __builtin_islessgreater(v1, v2);
|
||||
case kGeOrderedSignal: return v1 >= v2 && is_ordered;
|
||||
case kGtOrderedSignal: return v1 > v2 && is_ordered;
|
||||
case kTrueUnorderedQuiet: return true;
|
||||
case kEqOrderedSignal: return v1 == v2 && is_ordered;
|
||||
case kLtOrderedQuiet: return __builtin_isless(v1, v2);
|
||||
case kLeOrderedQuiet: return __builtin_islessequal(v1, v2);
|
||||
case kUnorderedSignal: return is_unordered;
|
||||
case kNeUnorderedSignal: return v1 != v2 || is_unordered;
|
||||
case kNltUnorderedQuiet: return !__builtin_isless(v1, v2);
|
||||
case kNleUnorderedQuiet: return !__builtin_islessequal(v1, v2);
|
||||
case kOrderedSignal: return is_ordered;
|
||||
case kEqUnorderedSignal: return v1 == v2 || is_unordered;
|
||||
case kNgeUnorderedQuiet: return !__builtin_isgreaterequal(v1, v2);
|
||||
case kNgtUnorderedQuiet: return !__builtin_isgreater(v1, v2);
|
||||
case kFalseOrderedSignal: return false;
|
||||
case kNeOrderedSignal: return !(v1 == v2) && is_ordered;
|
||||
case kGeOrderedQuiet: return __builtin_isgreaterequal(v1, v2);
|
||||
case kGtOrderedQuiet: return __builtin_isgreater(v1, v2);
|
||||
case kTrueUnorderedSignal: return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +156,6 @@ DEF_SEM(COMISD, S1 src1, S2 src2) {
|
||||
Write(FLAG_ZF, true);
|
||||
Write(FLAG_PF, false);
|
||||
Write(FLAG_CF, false);
|
||||
|
||||
}
|
||||
Write(FLAG_OF, false);
|
||||
Write(FLAG_SF, false);
|
||||
@@ -249,8 +217,7 @@ DEF_SEM(SHUFPS, D dst, S1 src1, S2 src2, I8 src3) {
|
||||
auto imm = Read(src3);
|
||||
auto num_groups = NumVectorElems(dst_vec);
|
||||
|
||||
_Pragma("unroll")
|
||||
for (std::size_t i = 0; i < num_groups; ++i) {
|
||||
_Pragma("unroll") for (std::size_t i = 0; i < num_groups; ++i) {
|
||||
auto order = UShr8(imm, TruncTo<uint8_t>(i * 2));
|
||||
auto sel = UAnd8(order, 0x3_u8);
|
||||
auto sel_val = UExtractV32(Select(i < 2, src1_vec, src2_vec), sel);
|
||||
@@ -276,8 +243,7 @@ DEF_SEM(SHUFPD, D dst, S1 src1, S2 src2, I8 src3) {
|
||||
auto imm = Read(src3);
|
||||
auto num_groups = NumVectorElems(src1_vec);
|
||||
|
||||
_Pragma("unroll")
|
||||
for (std::size_t i = 0; i < num_groups; i += 2) {
|
||||
_Pragma("unroll") for (std::size_t i = 0; i < num_groups; i += 2) {
|
||||
auto order = UShr8(imm, TruncTo<uint8_t>(i));
|
||||
auto sel1 = UAnd8(order, 0x1_u8);
|
||||
auto sel2 = Select(UAnd8(order, 0x2_u8) == 0x2_u8, 1_u8, 0_u8);
|
||||
@@ -303,13 +269,11 @@ DEF_SEM(PSHUFD, D dst, S1 src1, I8 src2) {
|
||||
auto src_vec = UReadV128(src1);
|
||||
auto num_groups = NumVectorElems(src_vec);
|
||||
|
||||
_Pragma("unroll")
|
||||
for (std::size_t i = 0, k = 0; i < num_groups; ++i) {
|
||||
_Pragma("unroll") for (std::size_t i = 0, k = 0; i < num_groups; ++i) {
|
||||
auto group = UExtractV128(src_vec, i);
|
||||
auto order = Read(src2);
|
||||
|
||||
_Pragma("unroll")
|
||||
for (std::size_t j = 0; j < 4; ++j, ++k) {
|
||||
_Pragma("unroll") for (std::size_t j = 0; j < 4; ++j, ++k) {
|
||||
auto sel = UAnd(order, 0x3_u8);
|
||||
auto shift = UMul(sel, 32_u8);
|
||||
order = UShr(order, 2_u8);
|
||||
@@ -343,6 +307,7 @@ namespace {
|
||||
|
||||
template <typename D, typename S1>
|
||||
DEF_SEM(PSHUFLW, D dst, S1 src1, I8 src2) {
|
||||
|
||||
// Source operand is packed with word (16-bit) integers to be shuffled,
|
||||
// but src1 is also a vector of one or more 128-bit "lanes":
|
||||
auto src_vec = UReadV128(src1);
|
||||
@@ -354,15 +319,16 @@ DEF_SEM(PSHUFLW, D dst, S1 src1, I8 src2) {
|
||||
// The same operation is done for each 128-bit "lane" of src1:
|
||||
auto num_lanes = NumVectorElems(UReadV128(src1));
|
||||
|
||||
_Pragma("unroll")
|
||||
for (std::size_t lane_index = 0, word_index = 0; lane_index < num_lanes; ++lane_index) {
|
||||
_Pragma("unroll") for (std::size_t lane_index = 0, word_index = 0;
|
||||
lane_index < num_lanes; ++lane_index) {
|
||||
auto lane = UExtractV128(src_vec, lane_index);
|
||||
|
||||
// Words will be shuffled in the order specified in a code in src2:
|
||||
auto order = Read(src2);
|
||||
|
||||
// Shuffle the 4 words from the low 64-bits of the 128-bit lane:
|
||||
_Pragma("unroll")
|
||||
for (std::size_t word_count = 0; word_count < 4; ++word_count, ++word_index) {
|
||||
_Pragma("unroll") for (std::size_t word_count = 0; word_count < 4;
|
||||
++word_count, ++word_index) {
|
||||
auto sel = UAnd(order, 0x3_u8);
|
||||
auto shift = UMul(sel, 16_u8);
|
||||
order = UShr(order, 2_u8);
|
||||
@@ -372,9 +338,10 @@ DEF_SEM(PSHUFLW, D dst, S1 src1, I8 src2) {
|
||||
|
||||
// After shuffling the low 64-bits, the high 64-bits of the src1 lane is
|
||||
// copied to the high quadword of the corresponding destination lane:
|
||||
_Pragma("unroll")
|
||||
for (std::size_t word_count = 0; word_count < 4; ++word_count, ++word_index) {
|
||||
dst_vec = UInsertV16(dst_vec, word_index, UExtractV16(src_words_vec, word_index));
|
||||
_Pragma("unroll") for (std::size_t word_count = 0; word_count < 4;
|
||||
++word_count, ++word_index) {
|
||||
dst_vec = UInsertV16(dst_vec, word_index,
|
||||
UExtractV16(src_words_vec, word_index));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,8 +356,7 @@ DEF_SEM(PSHUFHW, D dst, S1 src1, I8 src2) {
|
||||
auto imm = Read(src2);
|
||||
auto num_groups = NumVectorElems(src_vec);
|
||||
|
||||
_Pragma("unroll")
|
||||
for (std::size_t i = 4; i < num_groups; ++i) {
|
||||
_Pragma("unroll") for (std::size_t i = 4; i < num_groups; ++i) {
|
||||
auto order = UShr8(imm, TruncTo<uint8_t>((i - 4) * 2_u8));
|
||||
auto sel = UAnd8(order, 0x3_u8);
|
||||
auto sel_val = UExtractV16(src_vec, sel + 4);
|
||||
@@ -429,12 +395,11 @@ namespace {
|
||||
auto src2_vec = SReadV##size(src2); \
|
||||
auto dst_vec = SClearV##size(SReadV##size(dst)); \
|
||||
auto num_elems = NumVectorElems(src1_vec); \
|
||||
_Pragma("unroll") \
|
||||
for (std::size_t i = 0; i < num_elems; ++i) { \
|
||||
_Pragma("unroll") for (std::size_t i = 0; i < num_elems; ++i) { \
|
||||
auto src1_elem = SExtractV##size(src1_vec, i); \
|
||||
auto src2_elem = SExtractV##size(src2_vec, i); \
|
||||
auto res = Select<int ## size ## _t>( \
|
||||
op(src1_elem, src2_elem), -1_s ## size, 0_s ## size); \
|
||||
auto res = Select<int##size##_t>(op(src1_elem, src2_elem), -1_s##size, \
|
||||
0_s##size); \
|
||||
dst_vec = SInsertV##size(dst_vec, i, res); \
|
||||
} \
|
||||
SWriteV##size(dst, dst_vec); \
|
||||
@@ -535,8 +500,8 @@ DEF_SEM(CMPSS, D dst, S1 src1, S2 src2, I8 src3) {
|
||||
}
|
||||
auto v1 = FExtractV32(src1_vec, 0);
|
||||
auto v2 = FExtractV32(src2_vec, 0);
|
||||
bool cond = CompareFloats<float32_t>(
|
||||
static_cast<FloatCompareOperator>(op), v1, v2);
|
||||
bool cond =
|
||||
CompareFloats<float32_t>(static_cast<FloatCompareOperator>(op), v1, v2);
|
||||
|
||||
dst_vec = UInsertV32(dst_vec, 0, Select<uint32_t>(cond, ~0_u32, 0_u32));
|
||||
|
||||
@@ -555,8 +520,8 @@ DEF_SEM(CMPSD, D dst, S1 src1, S2 src2, I8 src3) {
|
||||
}
|
||||
auto v1 = FExtractV64(src1_vec, 0);
|
||||
auto v2 = FExtractV64(src2_vec, 0);
|
||||
bool cond = CompareFloats<float64_t>(
|
||||
static_cast<FloatCompareOperator>(op), v1, v2);
|
||||
bool cond =
|
||||
CompareFloats<float64_t>(static_cast<FloatCompareOperator>(op), v1, v2);
|
||||
|
||||
dst_vec = UInsertV64(dst_vec, 0, Select<uint64_t>(cond, ~0_u64, 0_u64));
|
||||
|
||||
@@ -595,13 +560,12 @@ DEF_SEM(CMPPS, D dst, S1 src1, S2 src2, I8 src3) {
|
||||
}
|
||||
|
||||
auto vec_count = NumVectorElems(src2_vec);
|
||||
_Pragma("unroll")
|
||||
for (std::size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (std::size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = FExtractV32(src1_vec, i);
|
||||
auto v2 = FExtractV32(src2_vec, i);
|
||||
|
||||
bool cond = CompareFloats<float32_t>(
|
||||
static_cast<FloatCompareOperator>(op), v1, v2);
|
||||
bool cond =
|
||||
CompareFloats<float32_t>(static_cast<FloatCompareOperator>(op), v1, v2);
|
||||
|
||||
auto res = Select<uint32_t>(cond, ~0_u32, 0_u32);
|
||||
dst_vec = UInsertV32(dst_vec, i, res);
|
||||
@@ -621,13 +585,12 @@ DEF_SEM(CMPPD, D dst, S1 src1, S2 src2, I8 src3) {
|
||||
}
|
||||
|
||||
auto vec_count = NumVectorElems(src2_vec);
|
||||
_Pragma("unroll")
|
||||
for (std::size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (std::size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = FExtractV64(src1_vec, i);
|
||||
auto v2 = FExtractV64(src2_vec, i);
|
||||
|
||||
bool cond = CompareFloats<float64_t>(
|
||||
static_cast<FloatCompareOperator>(op), v1, v2);
|
||||
bool cond =
|
||||
CompareFloats<float64_t>(static_cast<FloatCompareOperator>(op), v1, v2);
|
||||
|
||||
auto res = Select<uint64_t>(cond, ~0_u64, 0_u64);
|
||||
dst_vec = UInsertV64(dst_vec, i, res);
|
||||
@@ -660,12 +623,7 @@ DEF_ISEL(VCMPPD_YMMqq_YMMqq_YMMqq_IMMb) = CMPPD<VV256W, V256, V256>;
|
||||
|
||||
namespace {
|
||||
|
||||
enum InputFormat : uint8_t {
|
||||
kUInt8 = 0,
|
||||
kUInt16 = 1,
|
||||
kInt8 = 2,
|
||||
kInt16 = 3
|
||||
};
|
||||
enum InputFormat : uint8_t { kUInt8 = 0, kUInt16 = 1, kInt8 = 2, kInt16 = 3 };
|
||||
|
||||
enum AggregationOperation : uint8_t {
|
||||
kEqualAny = 0,
|
||||
@@ -718,16 +676,15 @@ class BitMatrix : std::bitset<x * y> {
|
||||
// src1 is a char set, src2 is a string. We set a bit of `int_res_1` to `1`
|
||||
// when a char in `src2` belongs to the char set `src1`.
|
||||
template <size_t num_elems>
|
||||
ALWAYS_INLINE static uint16_t AggregateEqualAny(
|
||||
const BitMatrix<num_elems, num_elems> &bool_res,
|
||||
ALWAYS_INLINE static uint16_t
|
||||
AggregateEqualAny(const BitMatrix<num_elems, num_elems> &bool_res,
|
||||
const size_t src1_len, const size_t src2_len) {
|
||||
|
||||
uint16_t int_res_1 = 0;
|
||||
uint16_t bit = 1;
|
||||
for (size_t j = 0; j < src2_len; ++j, bit <<= 1) {
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < src1_len; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < src1_len; ++i) {
|
||||
if (bool_res.Test(i, j)) {
|
||||
int_res_1 |= bit;
|
||||
break; // src2_j is in src1, at position src1_i.
|
||||
@@ -740,8 +697,8 @@ ALWAYS_INLINE static uint16_t AggregateEqualAny(
|
||||
// `src2` is a string, and `src1` is kind of like a the ranges of regular
|
||||
// expression character classes.
|
||||
template <size_t num_elems>
|
||||
ALWAYS_INLINE static uint16_t AggregateRanges(
|
||||
const BitMatrix<num_elems, num_elems> &bool_res,
|
||||
ALWAYS_INLINE static uint16_t
|
||||
AggregateRanges(const BitMatrix<num_elems, num_elems> &bool_res,
|
||||
const size_t src1_len, const size_t src2_len) {
|
||||
|
||||
uint16_t int_res_1 = 0;
|
||||
@@ -749,8 +706,7 @@ ALWAYS_INLINE static uint16_t AggregateRanges(
|
||||
|
||||
for (size_t j = 0; j < src2_len; ++j, bit <<= 1) {
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < (src1_len - 1); i += 2) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < (src1_len - 1); i += 2) {
|
||||
const auto geq_lower_bound = bool_res.Test(i, j);
|
||||
const auto leq_upper_bound = bool_res.Test(i + 1, j);
|
||||
if (geq_lower_bound && leq_upper_bound) {
|
||||
@@ -763,15 +719,14 @@ ALWAYS_INLINE static uint16_t AggregateRanges(
|
||||
}
|
||||
|
||||
template <size_t num_elems>
|
||||
ALWAYS_INLINE static uint16_t AggregateEqualEach(
|
||||
const BitMatrix<num_elems, num_elems> &bool_res,
|
||||
ALWAYS_INLINE static uint16_t
|
||||
AggregateEqualEach(const BitMatrix<num_elems, num_elems> &bool_res,
|
||||
const size_t src1_len, const size_t src2_len) {
|
||||
|
||||
uint16_t int_res_1 = 0;
|
||||
uint16_t bit = 1;
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < num_elems; ++i, bit <<= 1) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < num_elems; ++i, bit <<= 1) {
|
||||
const bool in_str1 = i < src1_len;
|
||||
const bool in_str2 = i < src2_len;
|
||||
if (in_str1 && in_str2) {
|
||||
@@ -787,8 +742,8 @@ ALWAYS_INLINE static uint16_t AggregateEqualEach(
|
||||
|
||||
// This is really `strstr`, i.e. searching for `src1` in `src2`.
|
||||
template <size_t num_elems>
|
||||
ALWAYS_INLINE static uint16_t AggregateEqualOrdered(
|
||||
const BitMatrix<num_elems, num_elems> &bool_res,
|
||||
ALWAYS_INLINE static uint16_t
|
||||
AggregateEqualOrdered(const BitMatrix<num_elems, num_elems> &bool_res,
|
||||
const size_t src1_len, const size_t src2_len) {
|
||||
|
||||
if (src1_len > src2_len) {
|
||||
@@ -800,8 +755,8 @@ ALWAYS_INLINE static uint16_t AggregateEqualOrdered(
|
||||
|
||||
for (size_t j = 0; j < num_elems; ++j, bit <<= 1) {
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0, k = j; i < (num_elems - j) && k < num_elems; ++i, ++k) {
|
||||
_Pragma("unroll") for (size_t i = 0, k = j;
|
||||
i < (num_elems - j) && k < num_elems; ++i, ++k) {
|
||||
auto needle_valid = i < src1_len;
|
||||
auto haystack_valid = k < src2_len;
|
||||
|
||||
@@ -824,15 +779,14 @@ DEF_SEM(DoPCMPISTRI, const V &src1, const V &src2,
|
||||
size_t src1_len = num_elems;
|
||||
size_t src2_len = num_elems;
|
||||
|
||||
const auto agg_operation = static_cast<AggregationOperation>(
|
||||
control.agg_operation);
|
||||
const auto agg_operation =
|
||||
static_cast<AggregationOperation>(control.agg_operation);
|
||||
|
||||
const auto polarity = static_cast<Polarity>(control.polarity);
|
||||
const auto output_selection = static_cast<OutputSelection>(
|
||||
control.output_selection);
|
||||
const auto output_selection =
|
||||
static_cast<OutputSelection>(control.output_selection);
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < num_elems; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < num_elems; ++i) {
|
||||
if (!src1.elems[i]) {
|
||||
src1_len = std::min<size_t>(src1_len, i);
|
||||
}
|
||||
@@ -844,16 +798,13 @@ DEF_SEM(DoPCMPISTRI, const V &src1, const V &src2,
|
||||
for (size_t n = 0; n < num_elems; ++n) {
|
||||
const auto reg = src1.elems[n];
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t m = 0; m < num_elems; ++m) {
|
||||
_Pragma("unroll") for (size_t m = 0; m < num_elems; ++m) {
|
||||
const auto reg_mem = src2.elems[m];
|
||||
|
||||
switch (agg_operation) {
|
||||
case kEqualAny:
|
||||
case kEqualEach:
|
||||
case kEqualOrdered:
|
||||
bool_res.Set(n, m, reg == reg_mem);
|
||||
break;
|
||||
case kEqualOrdered: bool_res.Set(n, m, reg == reg_mem); break;
|
||||
|
||||
// Checking is `src2[m]` is in the range of `src1[n]` and `src1[n+1]`.
|
||||
case kRanges:
|
||||
@@ -880,26 +831,21 @@ DEF_SEM(DoPCMPISTRI, const V &src1, const V &src2,
|
||||
int_res_1 = AggregateEqualEach<num_elems>(bool_res, src1_len, src2_len);
|
||||
break;
|
||||
case kEqualOrdered:
|
||||
int_res_1 = AggregateEqualOrdered<num_elems>(
|
||||
bool_res, src1_len, src2_len);
|
||||
int_res_1 =
|
||||
AggregateEqualOrdered<num_elems>(bool_res, src1_len, src2_len);
|
||||
break;
|
||||
}
|
||||
|
||||
uint16_t int_res_2 = 0;
|
||||
switch (polarity) {
|
||||
case kPositive:
|
||||
int_res_2 = int_res_1;
|
||||
break;
|
||||
case kPositive: int_res_2 = int_res_1; break;
|
||||
case kNegative:
|
||||
int_res_2 = (0xFFFF_u16 >> (16 - num_elems)) ^ int_res_1;
|
||||
break;
|
||||
case kMaskedPositive:
|
||||
int_res_2 = int_res_1;
|
||||
break;
|
||||
case kMaskedPositive: int_res_2 = int_res_1; break;
|
||||
case kMaskedNegative:
|
||||
int_res_2 = int_res_1;
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < num_elems; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < num_elems; ++i) {
|
||||
auto mask = static_cast<uint16_t>(1_u16 << i);
|
||||
if (i < src2_len) {
|
||||
int_res_2 ^= mask;
|
||||
@@ -967,8 +913,7 @@ DEF_SEM(PSRLDQ, D dst, S src1, I8 src2) {
|
||||
auto vec = UReadV8(src1);
|
||||
auto new_vec = UClearV8(UReadV8(dst));
|
||||
auto shift = std::min<size_t>(Read(src2), 16);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = shift, j = 0; i < 16; ++i, ++j) {
|
||||
_Pragma("unroll") for (size_t i = shift, j = 0; i < 16; ++i, ++j) {
|
||||
new_vec = UInsertV8(new_vec, j, UExtractV8(vec, i));
|
||||
}
|
||||
UWriteV8(dst, new_vec);
|
||||
@@ -982,8 +927,7 @@ DEF_SEM(VPSRLDQ, D dst, S src1, I8 src2) {
|
||||
auto vec = UReadV8(src1);
|
||||
auto new_vec = UClearV8(UReadV8(dst));
|
||||
auto shift = std::min<size_t>(Read(src2), 16);
|
||||
_Pragma("unroll")
|
||||
for (size_t i = shift, j = 0; i < 16; ++i, ++j) {
|
||||
_Pragma("unroll") for (size_t i = shift, j = 0; i < 16; ++i, ++j) {
|
||||
new_vec = UInsertV8(new_vec, j, UExtractV8(vec, i));
|
||||
new_vec = UInsertV8(new_vec, j + 16, UExtractV8(vec, i + 16));
|
||||
}
|
||||
@@ -1435,8 +1379,7 @@ DEF_SEM(MINPS, D dst, S1 src1, S2 src2) {
|
||||
auto src2_vec = FReadV32(src2);
|
||||
|
||||
auto vec_count = NumVectorElems(src2_vec);
|
||||
_Pragma("unroll")
|
||||
for (std::size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (std::size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = FExtractV32(dest_vec, i);
|
||||
auto v2 = FExtractV32(src2_vec, i);
|
||||
|
||||
@@ -1445,9 +1388,11 @@ DEF_SEM(MINPS, D dst, S1 src1, S2 src2) {
|
||||
// If either float is a NaN (SNaN or QNaN):
|
||||
if (__builtin_isunordered(v1, v2)) {
|
||||
min = v2;
|
||||
|
||||
// or if both floats are 0.0:
|
||||
} else if ((v1 == 0.0) && (v2 == 0.0)) {
|
||||
min = v2;
|
||||
|
||||
// or if src2 is less than src1:
|
||||
} else if (__builtin_isless(v2, v1)) {
|
||||
min = v2;
|
||||
@@ -1465,8 +1410,7 @@ DEF_SEM(MAXPS, D dst, S1 src1, S2 src2) {
|
||||
auto src2_vec = FReadV32(src2);
|
||||
|
||||
auto vec_count = NumVectorElems(src2_vec);
|
||||
_Pragma("unroll")
|
||||
for (std::size_t i = 0; i < vec_count; i++) {
|
||||
_Pragma("unroll") for (std::size_t i = 0; i < vec_count; i++) {
|
||||
auto v1 = FExtractV32(dest_vec, i);
|
||||
auto v2 = FExtractV32(src2_vec, i);
|
||||
|
||||
@@ -1475,9 +1419,11 @@ DEF_SEM(MAXPS, D dst, S1 src1, S2 src2) {
|
||||
// If either float is a NaN (SNaN or QNaN):
|
||||
if (__builtin_isunordered(v1, v2)) {
|
||||
max = v2;
|
||||
|
||||
// or if both floats are 0.0:
|
||||
} else if ((v1 == 0.0) && (v2 == 0.0)) {
|
||||
max = v2;
|
||||
|
||||
// or if src2 is greater than src1:
|
||||
} else if (__builtin_isgreater(v2, v1)) {
|
||||
max = v2;
|
||||
@@ -1489,7 +1435,7 @@ DEF_SEM(MAXPS, D dst, S1 src1, S2 src2) {
|
||||
return memory;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace
|
||||
|
||||
DEF_ISEL(MINPS_XMMps_MEMps) = MINPS<V128W, V128, MV128>;
|
||||
DEF_ISEL(MINPS_XMMps_XMMps) = MINPS<V128W, V128, V128>;
|
||||
@@ -1501,6 +1447,7 @@ namespace {
|
||||
|
||||
template <typename D, typename S1, typename S2>
|
||||
DEF_SEM(UNPCKLPS, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Initialize with a copy of src1 as a vector of 32-bit (DWORD) floats:
|
||||
auto temp_vec = FReadV32(src1);
|
||||
|
||||
@@ -1528,6 +1475,7 @@ DEF_SEM(UNPCKLPS, D dst, S1 src1, S2 src2) {
|
||||
|
||||
template <typename D, typename S1, typename S2>
|
||||
DEF_SEM(UNPCKLPD, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Initialize with a copy of src1 as a vector of 64-bit (QWORD) floats:
|
||||
auto temp_vec = FReadV64(src1);
|
||||
|
||||
@@ -1581,14 +1529,17 @@ namespace {
|
||||
|
||||
template <typename D, typename S1, typename S2>
|
||||
DEF_SEM(UNPCKHPD, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Initialize a working copy of src2 as a vector of 64-bit QWORDs.
|
||||
// This also accomplishes the "unpack" of the high QWORD of src2:
|
||||
auto temp_vec = FReadV64(src2);
|
||||
|
||||
// Treating src1 as another vector of 64-bit QWORDs:
|
||||
auto src1_vec = FReadV64(src1);
|
||||
auto src1_high_qword = FExtractV64(src1_vec, 1); // "unpack" high QWORD of src1
|
||||
temp_vec = FInsertV64(temp_vec, 0, src1_high_qword); // into low QWORD of temp
|
||||
auto src1_high_qword =
|
||||
FExtractV64(src1_vec, 1); // "unpack" high QWORD of src1
|
||||
temp_vec =
|
||||
FInsertV64(temp_vec, 0, src1_high_qword); // into low QWORD of temp
|
||||
|
||||
FWriteV64(dst, temp_vec); // SSE: Writes to XMM, AVX: Zero-extends XMM.
|
||||
return memory;
|
||||
@@ -1616,13 +1567,15 @@ namespace {
|
||||
|
||||
template <typename D, typename S1>
|
||||
DEF_SEM(MOVDDUP, D dst, S1 src) {
|
||||
|
||||
// Treat src as a vector of QWORD (64-bit) floats, even if it's just one element:
|
||||
auto src_vec = FReadV64(src);
|
||||
|
||||
// "Move and duplicate" QWORD src[63:0] into dest[63:0] and into dest[127:64]:
|
||||
auto src_float = FExtractV64(src_vec, 0);
|
||||
|
||||
float64v2_t temp_vec = {}; // length of src and dest may differ, so manually create.
|
||||
float64v2_t temp_vec =
|
||||
{}; // length of src and dest may differ, so manually create.
|
||||
temp_vec = FInsertV64(temp_vec, 0, src_float);
|
||||
temp_vec = FInsertV64(temp_vec, 1, src_float);
|
||||
|
||||
@@ -1655,6 +1608,7 @@ DEF_HELPER(SquareRoot32, float32_t src_float) -> float32_t {
|
||||
|
||||
// Special cases for invalid square root operations. See Intel manual, Table E-10.
|
||||
if (IsNaN(src_float)) {
|
||||
|
||||
// If src is SNaN, return the SNaN converted to a QNaN:
|
||||
if (IsSignalingNaN(src_float)) {
|
||||
nan32_t temp_nan = {src_float};
|
||||
@@ -1666,6 +1620,7 @@ DEF_HELPER(SquareRoot32, float32_t src_float) -> float32_t {
|
||||
square_root = src_float;
|
||||
}
|
||||
} else { // a number, that is, not a NaN
|
||||
|
||||
// A negative operand (except -0.0) results in the QNaN indefinite value.
|
||||
if (IsNegative(src_float) && src_float != -0.0) {
|
||||
uint32_t indef_qnan = 0xFFC00000U;
|
||||
@@ -1680,6 +1635,7 @@ DEF_HELPER(SquareRoot32, float32_t src_float) -> float32_t {
|
||||
|
||||
template <typename D, typename S1>
|
||||
DEF_SEM(SQRTSS, D dst, S1 src1) {
|
||||
|
||||
// Extract a "single-precision" (32-bit) float from [31:0] of src1 vector:
|
||||
auto src_float = FExtractV32(FReadV32(src1), 0);
|
||||
|
||||
@@ -1696,6 +1652,7 @@ DEF_SEM(SQRTSS, D dst, S1 src1) {
|
||||
#if HAS_FEATURE_AVX
|
||||
template <typename D, typename S1, typename S2>
|
||||
DEF_SEM(VSQRTSS, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Extract the single-precision float from [31:0] of the src2 vector:
|
||||
auto src_float = FExtractV32(FReadV32(src2), 0);
|
||||
|
||||
@@ -1732,10 +1689,12 @@ DEF_HELPER(SquareRoot64, float64_t src_float) -> float64_t {
|
||||
|
||||
// Special cases for invalid square root operations. See Intel manual, Table E-10.
|
||||
if (IsNaN(src_float)) {
|
||||
|
||||
// If src is SNaN, return the SNaN converted to a QNaN:
|
||||
if (IsSignalingNaN(src_float)) {
|
||||
nan64_t temp_nan = {src_float};
|
||||
temp_nan.is_quiet_nan = 1; // equivalent to a bitwise OR with 0x0008000000000000
|
||||
temp_nan.is_quiet_nan =
|
||||
1; // equivalent to a bitwise OR with 0x0008000000000000
|
||||
square_root = temp_nan.d;
|
||||
|
||||
// Else, src is a QNaN. Pass it directly to the result:
|
||||
@@ -1743,6 +1702,7 @@ DEF_HELPER(SquareRoot64, float64_t src_float) -> float64_t {
|
||||
square_root = src_float;
|
||||
}
|
||||
} else { // a number, that is, not a NaN
|
||||
|
||||
// A negative operand (except -0.0) results in the QNaN indefinite value.
|
||||
if (IsNegative(src_float) && src_float != -0.0) {
|
||||
uint64_t indef_qnan = 0xFFF8000000000000ULL;
|
||||
@@ -1757,6 +1717,7 @@ DEF_HELPER(SquareRoot64, float64_t src_float) -> float64_t {
|
||||
|
||||
template <typename D, typename S1>
|
||||
DEF_SEM(SQRTSD, D dst, S1 src1) {
|
||||
|
||||
// Extract a "double-precision" (64-bit) float from [63:0] of src1 vector:
|
||||
auto src_float = FExtractV64(FReadV64(src1), 0);
|
||||
|
||||
@@ -1773,6 +1734,7 @@ DEF_SEM(SQRTSD, D dst, S1 src1) {
|
||||
#if HAS_FEATURE_AVX
|
||||
template <typename D, typename S1, typename S2>
|
||||
DEF_SEM(VSQRTSD, D dst, S1 src1, S2 src2) {
|
||||
|
||||
// Extract the single-precision float from [63:0] of the src2 vector:
|
||||
auto src_float = FExtractV64(FReadV64(src2), 0);
|
||||
|
||||
@@ -1813,8 +1775,7 @@ DEF_SEM(PACKUSWB, D dst, S1 src1, S2 src2) {
|
||||
const auto num_elems = NumVectorElems(packed);
|
||||
const auto half_num_elems = num_elems / 2UL;
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < half_num_elems; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < half_num_elems; ++i) {
|
||||
auto val = SExtractV16(src1_vec, i);
|
||||
auto sat = std::max<int16_t>(std::min<int16_t>(val, 255), 0);
|
||||
packed.elems[i] = static_cast<uint8_t>(sat);
|
||||
@@ -1840,8 +1801,7 @@ DEF_SEM(PACKUSWB_AVX, D dst, S1 src1, S2 src2) {
|
||||
const auto half_num_elems = num_elems / 2UL;
|
||||
const auto quarter_num_elems = num_elems / 4UL;
|
||||
|
||||
_Pragma("unroll")
|
||||
for (size_t i = 0; i < quarter_num_elems; ++i) {
|
||||
_Pragma("unroll") for (size_t i = 0; i < quarter_num_elems; ++i) {
|
||||
auto val = SExtractV16(src1_vec, i);
|
||||
auto sat = std::max<int16_t>(std::min<int16_t>(val, 255), 0);
|
||||
packed.elems[i] = static_cast<uint8_t>(sat);
|
||||
@@ -1856,7 +1816,7 @@ DEF_SEM(PACKUSWB_AVX, D dst, S1 src1, S2 src2) {
|
||||
|
||||
auto val4 = SExtractV16(src2_vec, quarter_num_elems + i);
|
||||
auto sat4 = std::max<int16_t>(std::min<int16_t>(val4, 255), 0);
|
||||
packed.elems[half_num_elems + quarter_num_elems + i] = \
|
||||
packed.elems[half_num_elems + quarter_num_elems + i] =
|
||||
static_cast<uint8_t>(sat4);
|
||||
}
|
||||
|
||||
@@ -1872,10 +1832,14 @@ DEF_ISEL(PACKUSWB_MMXq_MEMq) = PACKUSWB<V64W, V64, MV64, uint8v8_t>;
|
||||
DEF_ISEL(PACKUSWB_MMXq_MMXq) = PACKUSWB<V64W, V64, V64, uint8v8_t>;
|
||||
DEF_ISEL(PACKUSWB_XMMdq_MEMdq) = PACKUSWB<V128W, V128, MV128, uint8v16_t>;
|
||||
DEF_ISEL(PACKUSWB_XMMdq_XMMdq) = PACKUSWB<V128W, V128, V128, uint8v16_t>;
|
||||
IF_AVX(DEF_ISEL(VPACKUSWB_XMMdq_XMMdq_MEMdq) = PACKUSWB<VV256W, V128, MV128, uint8v16_t>;)
|
||||
IF_AVX(DEF_ISEL(VPACKUSWB_XMMdq_XMMdq_XMMdq) = PACKUSWB<VV256W, V128, V128, uint8v16_t>;)
|
||||
IF_AVX(DEF_ISEL(VPACKUSWB_YMMqq_YMMqq_MEMqq) = PACKUSWB_AVX<VV256W, V256, MV256, uint8v32_t>;)
|
||||
IF_AVX(DEF_ISEL(VPACKUSWB_YMMqq_YMMqq_YMMqq) = PACKUSWB_AVX<VV256W, V256, V256, uint8v32_t>;)
|
||||
IF_AVX(DEF_ISEL(VPACKUSWB_XMMdq_XMMdq_MEMdq) =
|
||||
PACKUSWB<VV256W, V128, MV128, uint8v16_t>;)
|
||||
IF_AVX(DEF_ISEL(VPACKUSWB_XMMdq_XMMdq_XMMdq) =
|
||||
PACKUSWB<VV256W, V128, V128, uint8v16_t>;)
|
||||
IF_AVX(DEF_ISEL(VPACKUSWB_YMMqq_YMMqq_MEMqq) =
|
||||
PACKUSWB_AVX<VV256W, V256, MV256, uint8v32_t>;)
|
||||
IF_AVX(DEF_ISEL(VPACKUSWB_YMMqq_YMMqq_YMMqq) =
|
||||
PACKUSWB_AVX<VV256W, V256, V256, uint8v32_t>;)
|
||||
|
||||
/*
|
||||
555 PACKSSDW PACKSSDW_MMXq_MEMq MMX MMX PENTIUMMMX ATTRIBUTES: HALF_WIDE_OUTPUT NOTSX
|
||||
@@ -1938,14 +1902,11 @@ DEF_SEM(LDMXCSR, M32 src) {
|
||||
|
||||
if (!csr.rp && !csr.rn) {
|
||||
rounding_mode = FE_TONEAREST;
|
||||
}
|
||||
else if (!csr.rp && csr.rn) {
|
||||
} else if (!csr.rp && csr.rn) {
|
||||
rounding_mode = FE_DOWNWARD;
|
||||
}
|
||||
else if (csr.rp && !csr.rn) {
|
||||
} else if (csr.rp && !csr.rn) {
|
||||
rounding_mode = FE_UPWARD;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
rounding_mode = FE_TOWARDZERO;
|
||||
}
|
||||
fesetround(rounding_mode);
|
||||
|
||||
@@ -25,46 +25,46 @@ DEF_SEM(DoRDTSCP) {
|
||||
}
|
||||
|
||||
DEF_SEM(LGDT, M32 src) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
state.addr_to_load = AddressOf(src);
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86LoadGlobalDescriptorTable);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86LoadGlobalDescriptorTable);
|
||||
}
|
||||
|
||||
DEF_SEM(LIDT, M32 src) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
state.addr_to_load = AddressOf(src);
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86LoadInterruptDescriptorTable);
|
||||
}
|
||||
|
||||
DEF_SEM(DoRDMSR) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86ReadModelSpecificRegister);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86ReadModelSpecificRegister);
|
||||
}
|
||||
|
||||
DEF_SEM(DoWRMSR) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86WriteModelSpecificRegister);
|
||||
}
|
||||
|
||||
DEF_SEM(DoWBINVD) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86WriteBackInvalidate);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86WriteBackInvalidate);
|
||||
}
|
||||
|
||||
template <SyncHyperCall::Name kSetCR>
|
||||
DEF_SEM(WRITE_CONTROL_REG_32, R64W dst, R32 src) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
WriteZExt(dst, Read(src));
|
||||
auto u = __remill_undefined_8();
|
||||
Write(FLAG_OF, u);
|
||||
@@ -77,8 +77,8 @@ DEF_SEM(WRITE_CONTROL_REG_32, R64W dst, R32 src) {
|
||||
}
|
||||
|
||||
DEF_SEM(READ_CONTROL_REG_32, R32W dst, R64 src) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
WriteZExt(dst, Trunc(Read(src)));
|
||||
auto u = __remill_undefined_8();
|
||||
Write(FLAG_OF, u);
|
||||
@@ -92,8 +92,8 @@ DEF_SEM(READ_CONTROL_REG_32, R32W dst, R64 src) {
|
||||
|
||||
#if ADDRESS_SIZE_BITS == 64
|
||||
DEF_SEM(READ_CONTROL_REG_64, R64W dst, R64 src) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
Write(dst, Read(src));
|
||||
auto u = __remill_undefined_8();
|
||||
Write(FLAG_OF, u);
|
||||
@@ -107,8 +107,8 @@ DEF_SEM(READ_CONTROL_REG_64, R64W dst, R64 src) {
|
||||
|
||||
template <SyncHyperCall::Name kSetCR>
|
||||
DEF_SEM(WRITE_CONTROL_REG_64, R64W dst, R64 src) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
Write(dst, Read(src));
|
||||
auto u = __remill_undefined_8();
|
||||
Write(FLAG_OF, u);
|
||||
@@ -122,8 +122,8 @@ DEF_SEM(WRITE_CONTROL_REG_64, R64W dst, R64 src) {
|
||||
#endif
|
||||
|
||||
DEF_SEM(WRITE_DEBUG_REG_32, R64W dst, R32 src) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
WriteZExt(dst, Read(src));
|
||||
auto u = __remill_undefined_8();
|
||||
Write(FLAG_OF, u);
|
||||
@@ -132,14 +132,14 @@ DEF_SEM(WRITE_DEBUG_REG_32, R64W dst, R32 src) {
|
||||
Write(FLAG_AF, u);
|
||||
Write(FLAG_PF, u);
|
||||
Write(FLAG_CF, u);
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kX86SetDebugReg);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kX86SetDebugReg);
|
||||
}
|
||||
|
||||
#if ADDRESS_SIZE_BITS == 64
|
||||
DEF_SEM(WRITE_DEBUG_REG_64, R64W dst, R64 src) {
|
||||
memory = __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
memory =
|
||||
__remill_sync_hyper_call(state, memory, SyncHyperCall::kAssertPrivileged);
|
||||
Write(dst, Read(src));
|
||||
auto u = __remill_undefined_8();
|
||||
Write(FLAG_OF, u);
|
||||
@@ -148,8 +148,8 @@ DEF_SEM(WRITE_DEBUG_REG_64, R64W dst, R64 src) {
|
||||
Write(FLAG_AF, u);
|
||||
Write(FLAG_PF, u);
|
||||
Write(FLAG_CF, u);
|
||||
return __remill_sync_hyper_call(
|
||||
state, memory, SyncHyperCall::kAMD64SetDebugReg);
|
||||
return __remill_sync_hyper_call(state, memory,
|
||||
SyncHyperCall::kAMD64SetDebugReg);
|
||||
}
|
||||
#endif
|
||||
} // namespace
|
||||
@@ -161,18 +161,29 @@ DEF_ISEL(WRMSR) = DoWRMSR;
|
||||
DEF_ISEL(WBINVD) = DoWBINVD;
|
||||
DEF_ISEL(LGDT_MEMs_32) = LGDT;
|
||||
DEF_ISEL(LIDT_MEMs_32) = LIDT;
|
||||
DEF_ISEL(MOV_CR_CR_GPR32_CR0) = WRITE_CONTROL_REG_32<SyncHyperCall::kX86SetControlReg0>;
|
||||
DEF_ISEL(MOV_CR_CR_GPR32_CR1) = WRITE_CONTROL_REG_32<SyncHyperCall::kX86SetControlReg1>;
|
||||
DEF_ISEL(MOV_CR_CR_GPR32_CR2) = WRITE_CONTROL_REG_32<SyncHyperCall::kX86SetControlReg2>;
|
||||
DEF_ISEL(MOV_CR_CR_GPR32_CR3) = WRITE_CONTROL_REG_32<SyncHyperCall::kX86SetControlReg3>;
|
||||
DEF_ISEL(MOV_CR_CR_GPR32_CR4) = WRITE_CONTROL_REG_32<SyncHyperCall::kX86SetControlReg4>;
|
||||
DEF_ISEL(MOV_CR_CR_GPR32_CR0) =
|
||||
WRITE_CONTROL_REG_32<SyncHyperCall::kX86SetControlReg0>;
|
||||
DEF_ISEL(MOV_CR_CR_GPR32_CR1) =
|
||||
WRITE_CONTROL_REG_32<SyncHyperCall::kX86SetControlReg1>;
|
||||
DEF_ISEL(MOV_CR_CR_GPR32_CR2) =
|
||||
WRITE_CONTROL_REG_32<SyncHyperCall::kX86SetControlReg2>;
|
||||
DEF_ISEL(MOV_CR_CR_GPR32_CR3) =
|
||||
WRITE_CONTROL_REG_32<SyncHyperCall::kX86SetControlReg3>;
|
||||
DEF_ISEL(MOV_CR_CR_GPR32_CR4) =
|
||||
WRITE_CONTROL_REG_32<SyncHyperCall::kX86SetControlReg4>;
|
||||
DEF_ISEL(MOV_CR_GPR32_CR) = READ_CONTROL_REG_32;
|
||||
IF_64BIT(DEF_ISEL(MOV_CR_CR_GPR64_CR0) = WRITE_CONTROL_REG_64<SyncHyperCall::kAMD64SetControlReg0>;)
|
||||
IF_64BIT(DEF_ISEL(MOV_CR_CR_GPR64_CR1) = WRITE_CONTROL_REG_64<SyncHyperCall::kAMD64SetControlReg1>;)
|
||||
IF_64BIT(DEF_ISEL(MOV_CR_CR_GPR64_CR2) = WRITE_CONTROL_REG_64<SyncHyperCall::kAMD64SetControlReg2>;)
|
||||
IF_64BIT(DEF_ISEL(MOV_CR_CR_GPR64_CR3) = WRITE_CONTROL_REG_64<SyncHyperCall::kAMD64SetControlReg3>;)
|
||||
IF_64BIT(DEF_ISEL(MOV_CR_CR_GPR64_CR4) = WRITE_CONTROL_REG_64<SyncHyperCall::kAMD64SetControlReg4>;)
|
||||
IF_64BIT(DEF_ISEL(MOV_CR_CR_GPR64_CR8) = WRITE_CONTROL_REG_64<SyncHyperCall::kAMD64SetControlReg8>;)
|
||||
IF_64BIT(DEF_ISEL(MOV_CR_CR_GPR64_CR0) =
|
||||
WRITE_CONTROL_REG_64<SyncHyperCall::kAMD64SetControlReg0>;)
|
||||
IF_64BIT(DEF_ISEL(MOV_CR_CR_GPR64_CR1) =
|
||||
WRITE_CONTROL_REG_64<SyncHyperCall::kAMD64SetControlReg1>;)
|
||||
IF_64BIT(DEF_ISEL(MOV_CR_CR_GPR64_CR2) =
|
||||
WRITE_CONTROL_REG_64<SyncHyperCall::kAMD64SetControlReg2>;)
|
||||
IF_64BIT(DEF_ISEL(MOV_CR_CR_GPR64_CR3) =
|
||||
WRITE_CONTROL_REG_64<SyncHyperCall::kAMD64SetControlReg3>;)
|
||||
IF_64BIT(DEF_ISEL(MOV_CR_CR_GPR64_CR4) =
|
||||
WRITE_CONTROL_REG_64<SyncHyperCall::kAMD64SetControlReg4>;)
|
||||
IF_64BIT(DEF_ISEL(MOV_CR_CR_GPR64_CR8) =
|
||||
WRITE_CONTROL_REG_64<SyncHyperCall::kAMD64SetControlReg8>;)
|
||||
IF_64BIT(DEF_ISEL(MOV_CR_GPR64_CR) = READ_CONTROL_REG_64;)
|
||||
|
||||
DEF_ISEL(MOV_DR_DR_GPR32) = WRITE_DEBUG_REG_32;
|
||||
|
||||
@@ -27,14 +27,15 @@
|
||||
state.st.elems[2].val = state.st.elems[1].val; \
|
||||
state.st.elems[1].val = state.st.elems[0].val; \
|
||||
state.st.elems[0].val = __x; \
|
||||
state.x87.fxsave.swd.top = static_cast<uint16_t>( \
|
||||
(state.x87.fxsave.swd.top + 7) % 8); \
|
||||
state.x87.fxsave.swd.top = \
|
||||
static_cast<uint16_t>((state.x87.fxsave.swd.top + 7) % 8); \
|
||||
} while (false)
|
||||
|
||||
|
||||
// Ideally we'd want to assign `__remill_undefined_f64` to the last element,
|
||||
// but this more closely mimics the ring nature of the x87 stack.
|
||||
#define POP_X87_STACK() ({\
|
||||
#define POP_X87_STACK() \
|
||||
({ \
|
||||
auto __x = state.st.elems[0].val; \
|
||||
state.st.elems[0].val = state.st.elems[1].val; \
|
||||
state.st.elems[1].val = state.st.elems[2].val; \
|
||||
@@ -44,9 +45,10 @@
|
||||
state.st.elems[5].val = state.st.elems[6].val; \
|
||||
state.st.elems[6].val = state.st.elems[7].val; \
|
||||
state.st.elems[7].val = __x; \
|
||||
state.x87.fxsave.swd.top = static_cast<uint16_t>( \
|
||||
(state.x87.fxsave.swd.top + 9) % 8); \
|
||||
__x; })
|
||||
state.x87.fxsave.swd.top = \
|
||||
static_cast<uint16_t>((state.x87.fxsave.swd.top + 9) % 8); \
|
||||
__x; \
|
||||
})
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -67,8 +69,7 @@ namespace {
|
||||
IF_64BIT(state.x87.fxsave64.dp = AddressOf(mem);) \
|
||||
} while (false)
|
||||
|
||||
#define DEF_FPU_SEM(name, ...) \
|
||||
DEF_SEM(name, ##__VA_ARGS__, PC pc, I16 fop)
|
||||
#define DEF_FPU_SEM(name, ...) DEF_SEM(name, ##__VA_ARGS__, PC pc, I16 fop)
|
||||
|
||||
// TODO(joe): Loss of precision, see issue #199.
|
||||
DEF_FPU_SEM(FBLD, RF80W, MBCD80 src1) {
|
||||
@@ -80,8 +81,8 @@ DEF_FPU_SEM(FBLD, RF80W, MBCD80 src1) {
|
||||
double mag = 1.0; // Magnitude of decimal position
|
||||
|
||||
// Iterate through pairs of digits, encoded as bytes.
|
||||
_Pragma("unroll")
|
||||
for (addr_t i = 0; i < sizeof(src1_bcd.digit_pairs); i++) {
|
||||
_Pragma("unroll") for (addr_t i = 0; i < sizeof(src1_bcd.digit_pairs); i++) {
|
||||
|
||||
// We expect each half-byte to be a valid binary-coded decimal
|
||||
// digit (0-9). If not, the decoding result is undefined. The
|
||||
// native behavior seems to continue as if each encoding were
|
||||
@@ -730,9 +731,8 @@ template <typename T>
|
||||
DEF_FPU_SEM(FST, T dst, RF80 src) {
|
||||
SetFPUIpOp();
|
||||
typedef typename BaseType<T>::BT BT;
|
||||
auto res = CheckedFloatUnaryOp(state, [=] (float64_t x) {
|
||||
return static_cast<BT>(x);
|
||||
}, Read(src));
|
||||
auto res = CheckedFloatUnaryOp(
|
||||
state, [=](float64_t x) { return static_cast<BT>(x); }, Read(src));
|
||||
Write(dst, res);
|
||||
return memory;
|
||||
}
|
||||
@@ -785,8 +785,8 @@ DEF_HELPER(ConvertToInt, C1 cast, C2 convert, float64_t input)
|
||||
DEF_FPU_SEM(FISTm16, M16W dst, RF80 src) {
|
||||
SetFPUIpOp();
|
||||
SetFPUDp(dst);
|
||||
auto res = ConvertToInt(memory, state, Int16<float64_t>,
|
||||
Float64ToInt16, Read(src));
|
||||
auto res =
|
||||
ConvertToInt(memory, state, Int16<float64_t>, Float64ToInt16, Read(src));
|
||||
Write(dst, Unsigned(res));
|
||||
return memory;
|
||||
}
|
||||
@@ -794,8 +794,8 @@ DEF_FPU_SEM(FISTm16, M16W dst, RF80 src) {
|
||||
DEF_FPU_SEM(FISTm32, M32W dst, RF80 src) {
|
||||
SetFPUIpOp();
|
||||
SetFPUDp(dst);
|
||||
auto res = ConvertToInt(memory, state, Int32<float64_t>,
|
||||
Float64ToInt32, Read(src));
|
||||
auto res =
|
||||
ConvertToInt(memory, state, Int32<float64_t>, Float64ToInt32, Read(src));
|
||||
Write(dst, Unsigned(res));
|
||||
return memory;
|
||||
}
|
||||
@@ -815,8 +815,8 @@ DEF_FPU_SEM(FISTPm32, M32W dst, RF80 src) {
|
||||
DEF_FPU_SEM(FISTPm64, M64W dst, RF80 src) {
|
||||
SetFPUIpOp();
|
||||
SetFPUDp(dst);
|
||||
auto res = ConvertToInt(memory, state, Int64<float64_t>,
|
||||
Float64ToInt64, Read(src));
|
||||
auto res =
|
||||
ConvertToInt(memory, state, Int64<float64_t>, Float64ToInt64, Read(src));
|
||||
Write(dst, Unsigned(res));
|
||||
(void) POP_X87_STACK();
|
||||
return memory;
|
||||
@@ -887,8 +887,8 @@ namespace {
|
||||
DEF_FPU_SEM(FISTTPm16, M16W dst, RF80 src) {
|
||||
SetFPUIpOp();
|
||||
SetFPUDp(dst);
|
||||
auto res = TruncateToInt(memory, state, Int16<float64_t>,
|
||||
Float64ToInt16, Read(src));
|
||||
auto res =
|
||||
TruncateToInt(memory, state, Int16<float64_t>, Float64ToInt16, Read(src));
|
||||
Write(dst, Unsigned(res));
|
||||
(void) POP_X87_STACK();
|
||||
return memory;
|
||||
@@ -897,8 +897,8 @@ DEF_FPU_SEM(FISTTPm16, M16W dst, RF80 src) {
|
||||
DEF_FPU_SEM(FISTTPm32, M32W dst, RF80 src) {
|
||||
SetFPUIpOp();
|
||||
SetFPUDp(dst);
|
||||
auto res = TruncateToInt(memory, state, Int32<float64_t>,
|
||||
Float64ToInt32, Read(src));
|
||||
auto res =
|
||||
TruncateToInt(memory, state, Int32<float64_t>, Float64ToInt32, Read(src));
|
||||
Write(dst, Unsigned(res));
|
||||
(void) POP_X87_STACK();
|
||||
return memory;
|
||||
@@ -907,8 +907,8 @@ DEF_FPU_SEM(FISTTPm32, M32W dst, RF80 src) {
|
||||
DEF_FPU_SEM(FISTTPm64, M64W dst, RF80 src) {
|
||||
SetFPUIpOp();
|
||||
SetFPUDp(dst);
|
||||
auto res = TruncateToInt(memory, state, Int64<float64_t>,
|
||||
Float64ToInt64, Read(src));
|
||||
auto res =
|
||||
TruncateToInt(memory, state, Int64<float64_t>, Float64ToInt64, Read(src));
|
||||
Write(dst, Unsigned(res));
|
||||
(void) POP_X87_STACK();
|
||||
return memory;
|
||||
@@ -1064,6 +1064,7 @@ DEF_FPU_SEM(FUCOM, RF80 src1, S2 src2) {
|
||||
SetFPUIpOp();
|
||||
auto st0 = Read(src1);
|
||||
auto sti = Float64(Read(src2));
|
||||
|
||||
// Note: Don't modify c1. The docs only state that c1=0 if there was a
|
||||
// stack underflow.
|
||||
UnorderedCompare(memory, state, st0, sti);
|
||||
@@ -1075,6 +1076,7 @@ DEF_FPU_SEM(FCOM, RF80 src1, S2 src2) {
|
||||
SetFPUIpOp();
|
||||
auto st0 = Read(src1);
|
||||
auto sti = Float64(Read(src2));
|
||||
|
||||
// Note: Don't modify c1. The docs only state that c1=0 if there was a
|
||||
// stack underflow.
|
||||
OrderedCompare(memory, state, st0, sti);
|
||||
@@ -1276,21 +1278,14 @@ DEF_SEM(FNSTSW, D dst) {
|
||||
DEF_SEM(FNSTCW, M16W dst) {
|
||||
auto &cw = state.x87.fxsave.cwd;
|
||||
cw.pc = kPrecisionSingle;
|
||||
|
||||
//cw.flat = 0x027F_u16; // Our default, with double-precision.
|
||||
switch (fegetround()) {
|
||||
default:
|
||||
case FE_TONEAREST:
|
||||
cw.rc = kFPURoundToNearestEven;
|
||||
break;
|
||||
case FE_DOWNWARD:
|
||||
cw.rc = kFPURoundDownNegInf;
|
||||
break;
|
||||
case FE_UPWARD:
|
||||
cw.rc = kFPURoundUpInf;
|
||||
break;
|
||||
case FE_TOWARDZERO:
|
||||
cw.rc = kFPURoundToZero;
|
||||
break;
|
||||
case FE_TONEAREST: cw.rc = kFPURoundToNearestEven; break;
|
||||
case FE_DOWNWARD: cw.rc = kFPURoundDownNegInf; break;
|
||||
case FE_UPWARD: cw.rc = kFPURoundUpInf; break;
|
||||
case FE_TOWARDZERO: cw.rc = kFPURoundToZero; break;
|
||||
}
|
||||
Write(dst, cw.flat);
|
||||
return memory;
|
||||
@@ -1302,21 +1297,13 @@ DEF_SEM(FLDCW, M16 cwd) {
|
||||
cw.pc = kPrecisionSingle;
|
||||
int rounding_mode = FE_TONEAREST;
|
||||
switch (cw.rc) {
|
||||
case kFPURoundToNearestEven:
|
||||
rounding_mode = FE_TONEAREST;
|
||||
break;
|
||||
case kFPURoundToNearestEven: rounding_mode = FE_TONEAREST; break;
|
||||
|
||||
case kFPURoundDownNegInf:
|
||||
rounding_mode = FE_DOWNWARD;
|
||||
break;
|
||||
case kFPURoundDownNegInf: rounding_mode = FE_DOWNWARD; break;
|
||||
|
||||
case kFPURoundUpInf:
|
||||
rounding_mode = FE_UPWARD;
|
||||
break;
|
||||
case kFPURoundUpInf: rounding_mode = FE_UPWARD; break;
|
||||
|
||||
case kFPURoundToZero:
|
||||
rounding_mode = FE_TOWARDZERO;
|
||||
break;
|
||||
case kFPURoundToZero: rounding_mode = FE_TOWARDZERO; break;
|
||||
}
|
||||
fesetround(rounding_mode);
|
||||
return memory;
|
||||
@@ -1422,20 +1409,14 @@ DEF_FPU_SEM(FCMOVNB, D dst, S1 src1) {
|
||||
template <typename D, typename S1>
|
||||
DEF_FPU_SEM(FCMOVNBE, D dst, S1 src1) {
|
||||
SetFPUIpOp();
|
||||
Write(dst, Select(
|
||||
BNot(BOr(FLAG_CF, FLAG_ZF)),
|
||||
Read(src1),
|
||||
Read(dst)));
|
||||
Write(dst, Select(BNot(BOr(FLAG_CF, FLAG_ZF)), Read(src1), Read(dst)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
template <typename D, typename S1>
|
||||
DEF_FPU_SEM(FCMOVBE, D dst, S1 src1) {
|
||||
SetFPUIpOp();
|
||||
Write(dst, Select(
|
||||
BOr(FLAG_CF, FLAG_ZF),
|
||||
Read(src1),
|
||||
Read(dst)));
|
||||
Write(dst, Select(BOr(FLAG_CF, FLAG_ZF), Read(src1), Read(dst)));
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -1474,12 +1455,14 @@ DEF_ISEL(FCMOVB_ST0_X87) = FCMOVB<RF80W, RF80>;
|
||||
namespace {
|
||||
|
||||
DEF_SEM(DoFNINIT) {
|
||||
|
||||
// Initialize the FPU state without checking error conditions.
|
||||
// "Word" and opcode fields are always 16-bit. Pointer fields are either
|
||||
// 32-bit or 64-bit, but regardless, they are set to 0.
|
||||
state.x87.fsave.cwd.flat = 0x037F; // FPUControlWord
|
||||
state.x87.fsave.swd.flat = 0x0000; // FPUStatusWord
|
||||
state.x87.fsave.ftw.flat = 0x0000; // FPUTagWord (0xFFFF in the manual, 0x0000 in testing)
|
||||
state.x87.fsave.ftw.flat =
|
||||
0x0000; // FPUTagWord (0xFFFF in the manual, 0x0000 in testing)
|
||||
state.x87.fsave.dp = 0x0; // FPUDataPointer
|
||||
state.x87.fsave.ip = 0x0; // FPUInstructionPointer
|
||||
state.x87.fsave.fop = 0x0; // FPULastInstructionOpcode
|
||||
|
||||
@@ -38,9 +38,7 @@ DEF_SEM(DoXGETBV, PC next_pc) {
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
WriteZExt(REG_PC, Read(next_pc));
|
||||
StopFailure();
|
||||
default: WriteZExt(REG_PC, Read(next_pc)); StopFailure();
|
||||
}
|
||||
return memory;
|
||||
}
|
||||
|
||||
@@ -27,4 +27,3 @@ extern "C" {
|
||||
#include <xed/xed-interface.h>
|
||||
} // extern C
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
|
||||
+24
-20
@@ -22,35 +22,37 @@ const std::string BaseFunction::metadata_value = "base";
|
||||
|
||||
const std::string BaseFunction::metadata_kind = "remill.function.type";
|
||||
|
||||
const std::string LiftedFunction::metadata_value = BaseFunction::metadata_value + "." + "lifted";
|
||||
const std::string LiftedFunction::metadata_value =
|
||||
BaseFunction::metadata_value + "." + "lifted";
|
||||
|
||||
const std::string EntrypointFunction::metadata_value = BaseFunction::metadata_value + "." +
|
||||
"entrypoint";
|
||||
const std::string EntrypointFunction::metadata_value =
|
||||
BaseFunction::metadata_value + "." + "entrypoint";
|
||||
|
||||
const std::string ExternalFunction::metadata_value = BaseFunction::metadata_value + "." +
|
||||
"external";
|
||||
const std::string ExternalFunction::metadata_value =
|
||||
BaseFunction::metadata_value + "." + "external";
|
||||
|
||||
const std::string AbiLibraries::metadata_value = ExternalFunction::metadata_value + "." +
|
||||
"abilibraries";
|
||||
const std::string AbiLibraries::metadata_value =
|
||||
ExternalFunction::metadata_value + "." + "abilibraries";
|
||||
|
||||
const std::string CFGExternal::metadata_value = ExternalFunction::metadata_value + "." +
|
||||
"cfgexternal";
|
||||
const std::string CFGExternal::metadata_value =
|
||||
ExternalFunction::metadata_value + "." + "cfgexternal";
|
||||
|
||||
const std::string ExtWrapper::metadata_value = ExternalFunction::metadata_value + "." +
|
||||
"extwrapper";
|
||||
const std::string ExtWrapper::metadata_value =
|
||||
ExternalFunction::metadata_value + "." + "extwrapper";
|
||||
|
||||
|
||||
const std::string Helper::metadata_value = BaseFunction::metadata_value + "." + "helper";
|
||||
const std::string Helper::metadata_value =
|
||||
BaseFunction::metadata_value + "." + "helper";
|
||||
|
||||
|
||||
const std::string RemillHelper::metadata_value = Helper::metadata_value + "." +
|
||||
"remill";
|
||||
const std::string RemillHelper::metadata_value =
|
||||
Helper::metadata_value + "." + "remill";
|
||||
|
||||
const std::string McSemaHelper::metadata_value = Helper::metadata_value + "." +
|
||||
"mcsema";
|
||||
const std::string McSemaHelper::metadata_value =
|
||||
Helper::metadata_value + "." + "mcsema";
|
||||
|
||||
const std::string Semantics::metadata_value = Helper::metadata_value + "." +
|
||||
"semantics";
|
||||
const std::string Semantics::metadata_value =
|
||||
Helper::metadata_value + "." + "semantics";
|
||||
|
||||
#if LLVM_VERSION_NUMBER >= LLVM_VERSION(4, 0)
|
||||
|
||||
@@ -63,7 +65,8 @@ llvm::MDNode *TieFunction(llvm::Function *first, llvm::Function *second,
|
||||
}
|
||||
|
||||
std::pair<llvm::MDNode *, llvm::MDNode *>
|
||||
TieFunctions(llvm::Function *first, llvm::Function *second, const std::string &kind) {
|
||||
TieFunctions(llvm::Function *first, llvm::Function *second,
|
||||
const std::string &kind) {
|
||||
LOG_IF(FATAL, IsTied(first, kind) || IsTied(second, kind))
|
||||
<< "Tried to tie already tied functions " << first->getName().str()
|
||||
<< " to " << second->getName().str();
|
||||
@@ -81,7 +84,8 @@ llvm::Function *GetTied(llvm::Function *func, const std::string &kind) {
|
||||
auto casted = llvm::dyn_cast<llvm::ConstantAsMetadata>(node->getOperand(0));
|
||||
|
||||
if (!casted) {
|
||||
DLOG(INFO) << func->getName().str() << " with kind " << kind << " was tied to nullptr";
|
||||
DLOG(INFO) << func->getName().str() << " with kind " << kind
|
||||
<< " was tied to nullptr";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
+59
-53
@@ -16,18 +16,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include <llvm/IR/Metadata.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Metadata.h>
|
||||
|
||||
#include "remill/BC/Version.h"
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
namespace remill {
|
||||
|
||||
// For all function holds that OriginType should have two static strings
|
||||
@@ -37,6 +36,7 @@ namespace remill {
|
||||
|
||||
struct BaseFunction {
|
||||
static const std::string metadata_kind;
|
||||
|
||||
// Each class that inherits from some parent class appends its own metadata_value string with dot
|
||||
// to the parents one, therefore it is possible for search to easily include all subclasses as well
|
||||
static const std::string metadata_value;
|
||||
@@ -87,7 +87,8 @@ static llvm::MDNode *GetNode(llvm::Function *func) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto metadata_s = llvm::dyn_cast<llvm::MDString>(metadata_node->getOperand(0));
|
||||
auto metadata_s =
|
||||
llvm::dyn_cast<llvm::MDString>(metadata_node->getOperand(0));
|
||||
return (Contains<OriginType>(metadata_s)) ? metadata_node : nullptr;
|
||||
}
|
||||
|
||||
@@ -106,9 +107,11 @@ static bool Remove(llvm::Function *func) {
|
||||
template <typename OriginType>
|
||||
static void Annotate(llvm::Function *func) {
|
||||
auto &C = func->getContext();
|
||||
DLOG(INFO) << "Annotating: " << func->getName().str() << ": " << OriginType::metadata_kind
|
||||
<< " -> " << OriginType::metadata_value;
|
||||
auto node = llvm::MDNode::get(C, llvm::MDString::get(C, OriginType::metadata_value));
|
||||
DLOG(INFO) << "Annotating: " << func->getName().str() << ": "
|
||||
<< OriginType::metadata_kind << " -> "
|
||||
<< OriginType::metadata_value;
|
||||
auto node =
|
||||
llvm::MDNode::get(C, llvm::MDString::get(C, OriginType::metadata_value));
|
||||
func->setMetadata(OriginType::metadata_kind, node);
|
||||
}
|
||||
|
||||
@@ -119,7 +122,8 @@ static bool HasOriginType(llvm::Function *func) {
|
||||
|
||||
template <typename Type, typename Second, typename... OriginTypes>
|
||||
static bool HasOriginType(llvm::Function *func) {
|
||||
return HasOriginType<Type>(func) || HasOriginType<Second, OriginTypes...>(func);
|
||||
return HasOriginType<Type>(func) ||
|
||||
HasOriginType<Second, OriginTypes...>(func);
|
||||
}
|
||||
|
||||
// Return list of functions that are one of chosen OriginType
|
||||
@@ -127,6 +131,7 @@ template<typename Container, typename ... OriginTypes>
|
||||
static void GetFunctionsByOrigin(llvm::Module &module, Container &result) {
|
||||
for (auto &func : module) {
|
||||
if (HasOriginType<OriginTypes...>(&func)) {
|
||||
|
||||
// Method that is both in std::set and std::vector
|
||||
result.insert(result.end(), &func);
|
||||
}
|
||||
@@ -159,11 +164,13 @@ static bool ChangeOriginType(llvm::Function *func) {
|
||||
*/
|
||||
|
||||
// Get node that is holding the tie information
|
||||
static inline llvm::MDNode *GetTieNode(llvm::Function *func, const std::string &kind = TieKind) {
|
||||
static inline llvm::MDNode *GetTieNode(llvm::Function *func,
|
||||
const std::string &kind = TieKind) {
|
||||
return func->getMetadata(kind);
|
||||
}
|
||||
|
||||
static inline bool IsTied(llvm::Function *func, const std::string& kind = TieKind) {
|
||||
static inline bool IsTied(llvm::Function *func,
|
||||
const std::string &kind = TieKind) {
|
||||
return GetTieNode(func, kind);
|
||||
}
|
||||
|
||||
@@ -172,19 +179,20 @@ llvm::MDNode *TieFunction(llvm::Function *first, llvm::Function *second,
|
||||
const std::string &kind = TieKind);
|
||||
|
||||
std::pair<llvm::MDNode *, llvm::MDNode *>
|
||||
TieFunctions(llvm::Function *first, llvm::Function *second, const std::string &kind = TieKind);
|
||||
TieFunctions(llvm::Function *first, llvm::Function *second,
|
||||
const std::string &kind = TieKind);
|
||||
|
||||
// Get function that is tied to func, or nullptr if there is no such function
|
||||
llvm::Function *GetTied(llvm::Function *func, const std::string &kind = TieKind);
|
||||
llvm::Function *GetTied(llvm::Function *func,
|
||||
const std::string &kind = TieKind);
|
||||
|
||||
|
||||
/* Filter Tied functions in meaningful way. Several overloads are prepared depending on customization
|
||||
* required.
|
||||
*/
|
||||
template <typename BinaryPredicate>
|
||||
static void GetTieMapping(
|
||||
llvm::Module &module,
|
||||
BinaryPredicate pred,
|
||||
static void
|
||||
GetTieMapping(llvm::Module &module, BinaryPredicate pred,
|
||||
std::unordered_map<llvm::Function *, llvm::Function *> &result,
|
||||
const std::string &kind = TieKind) {
|
||||
|
||||
@@ -198,9 +206,8 @@ static void GetTieMapping(
|
||||
|
||||
// TODO(C++14): Deduced return types
|
||||
template <typename BinaryPredicate, typename Container>
|
||||
static std::unordered_map<llvm::Function *, llvm::Function *> GetTieMapping(
|
||||
llvm::Module &module,
|
||||
BinaryPredicate pred,
|
||||
static std::unordered_map<llvm::Function *, llvm::Function *>
|
||||
GetTieMapping(llvm::Module &module, BinaryPredicate pred,
|
||||
const Container &kinds) {
|
||||
|
||||
std::unordered_map<llvm::Function *, llvm::Function *> result;
|
||||
@@ -214,9 +221,8 @@ static std::unordered_map<llvm::Function *, llvm::Function *> GetTieMapping(
|
||||
// If functions are annotated with OriginTypes, this overload filters based on these annotations.
|
||||
template <typename FromType, typename ToType = BaseFunction,
|
||||
typename Container = std::vector<std::string>>
|
||||
static std::unordered_map<llvm::Function *, llvm::Function *> GetTieMapping(
|
||||
llvm::Module &module,
|
||||
const Container &kinds) {
|
||||
static std::unordered_map<llvm::Function *, llvm::Function *>
|
||||
GetTieMapping(llvm::Module &module, const Container &kinds) {
|
||||
|
||||
auto filter = [](llvm::Function *from, llvm::Function *to) {
|
||||
return HasOriginType<FromType>(from) && HasOriginType<ToType>(to);
|
||||
@@ -226,28 +232,28 @@ static std::unordered_map<llvm::Function *, llvm::Function *> GetTieMapping(
|
||||
|
||||
// TODO(C++14): Deduced return types
|
||||
template <typename FromType, typename ToType = BaseFunction>
|
||||
static std::unordered_map<llvm::Function *, llvm::Function *> GetTieMapping(
|
||||
llvm::Module &module,
|
||||
const std::string &kind = TieKind) {
|
||||
static std::unordered_map<llvm::Function *, llvm::Function *>
|
||||
GetTieMapping(llvm::Module &module, const std::string &kind = TieKind) {
|
||||
|
||||
return GetTieMapping<FromType, ToType>(module, std::vector<std::string>{ kind });
|
||||
return GetTieMapping<FromType, ToType>(module,
|
||||
std::vector<std::string>{kind});
|
||||
}
|
||||
|
||||
|
||||
static inline std::unordered_map<llvm::Function *, llvm::Function *> GetTieMapping(
|
||||
llvm::Module &module,
|
||||
const std::string &kind = TieKind) {
|
||||
static inline std::unordered_map<llvm::Function *, llvm::Function *>
|
||||
GetTieMapping(llvm::Module &module, const std::string &kind = TieKind) {
|
||||
|
||||
// TODO(C++14): auto in lambda
|
||||
return GetTieMapping (module,
|
||||
[](llvm::Function *, llvm::Function *) { return true; },
|
||||
return GetTieMapping(
|
||||
module, [](llvm::Function *, llvm::Function *) { return true; },
|
||||
std::vector<std::string>{kind});
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
# define NOT_AVAILABLE(Err) \
|
||||
LOG(Err) <<"LLVM version is less than 4.0, functions metadata are not avalaible"
|
||||
LOG(Err) \
|
||||
<< "LLVM version is less than 4.0, functions metadata are not avalaible"
|
||||
|
||||
template <typename OriginType>
|
||||
static bool Contains(llvm::MDString *node) {
|
||||
@@ -307,46 +313,49 @@ static bool ChangeOriginType(llvm::Function *func) {
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline llvm::MDNode *GetTieNode(llvm::Function *func, const std::string &kind = TieKind) {
|
||||
static inline llvm::MDNode *GetTieNode(llvm::Function *func,
|
||||
const std::string &kind = TieKind) {
|
||||
NOT_AVAILABLE(ERROR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline bool IsTied(llvm::Function *func, const std::string& kind = TieKind) {
|
||||
static inline bool IsTied(llvm::Function *func,
|
||||
const std::string &kind = TieKind) {
|
||||
NOT_AVAILABLE(ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline llvm::MDNode *TieFunction(llvm::Function *first, llvm::Function *second,
|
||||
static inline llvm::MDNode *TieFunction(llvm::Function *first,
|
||||
llvm::Function *second,
|
||||
const std::string &kind = TieKind) {
|
||||
NOT_AVAILABLE(ERROR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline std::pair<llvm::MDNode *, llvm::MDNode *>
|
||||
TieFunctions(llvm::Function *first, llvm::Function *second, const std::string &kind = TieKind) {
|
||||
TieFunctions(llvm::Function *first, llvm::Function *second,
|
||||
const std::string &kind = TieKind) {
|
||||
NOT_AVAILABLE(ERROR);
|
||||
return {};
|
||||
}
|
||||
|
||||
static inline llvm::Function *GetTied(llvm::Function *func, const std::string &kind = TieKind) {
|
||||
static inline llvm::Function *GetTied(llvm::Function *func,
|
||||
const std::string &kind = TieKind) {
|
||||
NOT_AVAILABLE(ERROR);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename BinaryPredicate>
|
||||
static void GetTieMapping(
|
||||
llvm::Module &module,
|
||||
BinaryPredicate pred,
|
||||
static void
|
||||
GetTieMapping(llvm::Module &module, BinaryPredicate pred,
|
||||
std::unordered_map<llvm::Function *, llvm::Function *> &result,
|
||||
const std::string &kind = TieKind) {
|
||||
NOT_AVAILABLE(ERROR);
|
||||
}
|
||||
|
||||
template <typename BinaryPredicate, typename Container>
|
||||
static std::unordered_map<llvm::Function *, llvm::Function *> GetTieMapping(
|
||||
llvm::Module &module,
|
||||
BinaryPredicate pred,
|
||||
static std::unordered_map<llvm::Function *, llvm::Function *>
|
||||
GetTieMapping(llvm::Module &module, BinaryPredicate pred,
|
||||
const Container &kinds) {
|
||||
NOT_AVAILABLE(ERROR);
|
||||
return {};
|
||||
@@ -354,24 +363,21 @@ static std::unordered_map<llvm::Function *, llvm::Function *> GetTieMapping(
|
||||
|
||||
template <typename FromType, typename ToType = BaseFunction,
|
||||
typename Container = std::vector<std::string>>
|
||||
static std::unordered_map<llvm::Function *, llvm::Function *> GetTieMapping(
|
||||
llvm::Module &module,
|
||||
const Container &kinds) {
|
||||
static std::unordered_map<llvm::Function *, llvm::Function *>
|
||||
GetTieMapping(llvm::Module &module, const Container &kinds) {
|
||||
NOT_AVAILABLE(ERROR);
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename FromType, typename ToType = BaseFunction>
|
||||
static std::unordered_map<llvm::Function *, llvm::Function *> GetTieMapping(
|
||||
llvm::Module &module,
|
||||
const std::string &kind = TieKind) {
|
||||
static std::unordered_map<llvm::Function *, llvm::Function *>
|
||||
GetTieMapping(llvm::Module &module, const std::string &kind = TieKind) {
|
||||
NOT_AVAILABLE(ERROR);
|
||||
return {};
|
||||
}
|
||||
|
||||
static inline std::unordered_map<llvm::Function *, llvm::Function *> GetTieMapping(
|
||||
llvm::Module &module,
|
||||
const std::string &kind = TieKind) {
|
||||
static inline std::unordered_map<llvm::Function *, llvm::Function *>
|
||||
GetTieMapping(llvm::Module &module, const std::string &kind = TieKind) {
|
||||
NOT_AVAILABLE(ERROR);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -18,8 +18,8 @@ inline static llvm::TypeSize BitsToTypeSize(uint64_t size) {
|
||||
}
|
||||
#endif
|
||||
|
||||
inline static uint64_t SizeOfTypeInBits(
|
||||
const llvm::DataLayout &data_layout, llvm::Type *type) {
|
||||
inline static uint64_t SizeOfTypeInBits(const llvm::DataLayout &data_layout,
|
||||
llvm::Type *type) {
|
||||
return TypeSizeToBits(data_layout.getTypeSizeInBits(type));
|
||||
}
|
||||
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <system_error>
|
||||
|
||||
#include <llvm/Support/ErrorOr.h>
|
||||
#include <llvm/Support/Format.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
|
||||
#include <system_error>
|
||||
|
||||
#include "remill/BC/Version.h"
|
||||
|
||||
#if LLVM_VERSION_NUMBER >= LLVM_VERSION(3, 9)
|
||||
@@ -63,9 +63,8 @@ inline static std::string GetErrorString(llvm::ErrorOr<T> &val) {
|
||||
inline static std::string GetErrorString(llvm::Error &val) {
|
||||
std::string err;
|
||||
llvm::raw_string_ostream os(err);
|
||||
llvm::handleAllErrors(std::move(val), [&os] (llvm::ErrorInfoBase &eib) {
|
||||
eib.log(os);
|
||||
});
|
||||
llvm::handleAllErrors(std::move(val),
|
||||
[&os](llvm::ErrorInfoBase &eib) { eib.log(os); });
|
||||
os.flush();
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "remill/BC/Version.h"
|
||||
|
||||
#include <llvm/IR/GlobalValue.h>
|
||||
|
||||
#include "remill/BC/Version.h"
|
||||
|
||||
namespace remill {
|
||||
|
||||
inline static llvm::Type *GetValueType(llvm::GlobalValue *global) {
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <llvm/IRReader/IRReader.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "remill/BC/Version.h"
|
||||
|
||||
#include <llvm/IRReader/IRReader.h>
|
||||
|
||||
#if LLVM_VERSION_NUMBER < LLVM_VERSION(3, 6)
|
||||
|
||||
namespace llvm {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "remill/BC/Version.h"
|
||||
|
||||
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
||||
#include <llvm/ExecutionEngine/RTDyldMemoryManager.h>
|
||||
#include <llvm/ExecutionEngine/RuntimeDyld.h>
|
||||
|
||||
#include "remill/BC/Version.h"
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "remill/BC/Version.h"
|
||||
|
||||
#include <llvm/Transforms/Scalar.h>
|
||||
|
||||
#include "remill/BC/Version.h"
|
||||
|
||||
#if LLVM_VERSION_NUMBER >= LLVM_VERSION(7, 0)
|
||||
# include <llvm/Transforms/Utils.h>
|
||||
#endif
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "remill/BC/Version.h"
|
||||
#include <llvm/Support/ToolOutputFile.h>
|
||||
|
||||
#include "remill/BC/Version.h"
|
||||
|
||||
#if LLVM_VERSION_NUMBER < LLVM_VERSION(6, 0)
|
||||
namespace llvm {
|
||||
using ToolOutputFile = tool_output_file;
|
||||
|
||||
+110
-155
@@ -14,8 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include "remill/BC/DeadStoreEliminator.h"
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
#include <llvm/IR/BasicBlock.h>
|
||||
#include <llvm/IR/CFG.h>
|
||||
#include <llvm/IR/InstVisitor.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/Transforms/Utils/Local.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <fstream>
|
||||
@@ -25,18 +33,10 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <llvm/IR/BasicBlock.h>
|
||||
#include <llvm/IR/CFG.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/InstVisitor.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/Transforms/Utils/Local.h>
|
||||
|
||||
#include "ABI.h"
|
||||
#include "remill/Arch/Arch.h"
|
||||
#include "remill/BC/DeadStoreEliminator.h"
|
||||
#include "remill/BC/Util.h"
|
||||
#include "remill/OS/FileSystem.h"
|
||||
#include "ABI.h"
|
||||
|
||||
DEFINE_string(dot_output_dir, "",
|
||||
"The directory in which to log DOT digraphs of the alias "
|
||||
@@ -92,8 +92,7 @@ struct KillCounter {
|
||||
// (and not the `__remill_basic_block`).
|
||||
static bool IsLiftedFunction(llvm::Function *func,
|
||||
const llvm::Function *bb_func) {
|
||||
return !(func == bb_func ||
|
||||
func->isDeclaration() ||
|
||||
return !(func == bb_func || func->isDeclaration() ||
|
||||
func->getFunctionType() != bb_func->getFunctionType());
|
||||
}
|
||||
|
||||
@@ -132,8 +131,7 @@ StateVisitor::StateVisitor(llvm::DataLayout *dl_, uint64_t num_bytes)
|
||||
// offset that is within the element's begin offset and end offset.
|
||||
void StateVisitor::Visit(llvm::Type *ty) {
|
||||
if (!ty) { // TODO(tim): Is this even possible?
|
||||
LOG(FATAL)
|
||||
<< "NULL type in `State` structure.";
|
||||
LOG(FATAL) << "NULL type in `State` structure.";
|
||||
}
|
||||
|
||||
uint64_t num_bytes = dl->getTypeAllocSize(ty);
|
||||
@@ -152,9 +150,9 @@ void StateVisitor::Visit(llvm::Type *ty) {
|
||||
const auto elem_ty = struct_ty->getElementType(i);
|
||||
|
||||
if (elem_offset != offset) {
|
||||
LOG(ERROR)
|
||||
<< "Element " << i << " of type " << LLVMThingToString(elem_ty)
|
||||
<< " in " << LLVMThingToString(ty) << " has padding";
|
||||
LOG(ERROR) << "Element " << i << " of type "
|
||||
<< LLVMThingToString(elem_ty) << " in "
|
||||
<< LLVMThingToString(ty) << " has padding";
|
||||
CHECK_LT(offset, elem_offset);
|
||||
for (auto j = offset; j < elem_offset; ++j) {
|
||||
offset_to_slot.emplace_back(~0u, ~0u, ~0u);
|
||||
@@ -192,13 +190,15 @@ void StateVisitor::Visit(llvm::Type *ty) {
|
||||
} else {
|
||||
auto num_elems = num_bytes / el_num_bytes;
|
||||
for (uint64_t i = 0; i < num_elems; i++) {
|
||||
|
||||
// NOTE(tim): Recalculates every time, rather than memoizing.
|
||||
Visit(first_ty);
|
||||
}
|
||||
}
|
||||
|
||||
// Primitive type.
|
||||
} else if (ty->isIntegerTy() || ty->isFloatingPointTy() || ty->isPointerTy()) {
|
||||
} else if (ty->isIntegerTy() || ty->isFloatingPointTy() ||
|
||||
ty->isPointerTy()) {
|
||||
for (uint64_t i = 0; i < num_bytes; i++) {
|
||||
offset_to_slot.emplace_back(index, offset, num_bytes);
|
||||
}
|
||||
@@ -206,8 +206,7 @@ void StateVisitor::Visit(llvm::Type *ty) {
|
||||
offset += num_bytes;
|
||||
|
||||
} else {
|
||||
LOG(FATAL)
|
||||
<< "Unexpected type `" << LLVMThingToString(ty)
|
||||
LOG(FATAL) << "Unexpected type `" << LLVMThingToString(ty)
|
||||
<< "` in state structure";
|
||||
}
|
||||
|
||||
@@ -215,8 +214,7 @@ void StateVisitor::Visit(llvm::Type *ty) {
|
||||
}
|
||||
|
||||
// Try to get the offset associated with some value.
|
||||
static bool TryGetOffset(llvm::Value *val,
|
||||
const ValueToOffset &state_offset,
|
||||
static bool TryGetOffset(llvm::Value *val, const ValueToOffset &state_offset,
|
||||
uint64_t *offset_out) {
|
||||
auto ptr = state_offset.find(val);
|
||||
if (ptr != state_offset.end()) {
|
||||
@@ -230,8 +228,8 @@ static bool TryGetOffset(llvm::Value *val,
|
||||
|
||||
// Try to get the offset associated with some value, or if the value is
|
||||
// a constant integer, get that instead.
|
||||
static bool TryGetOffsetOrConst(
|
||||
llvm::Value *val, const ValueToOffset &state_offset,
|
||||
static bool TryGetOffsetOrConst(llvm::Value *val,
|
||||
const ValueToOffset &state_offset,
|
||||
uint64_t *offset_out) {
|
||||
if (auto const_val = llvm::dyn_cast<llvm::ConstantInt>(val)) {
|
||||
const auto &val_apint = const_val->getValue();
|
||||
@@ -239,8 +237,8 @@ static bool TryGetOffsetOrConst(
|
||||
*offset_out = static_cast<uint64_t>(const_val->getSExtValue());
|
||||
return true;
|
||||
} else {
|
||||
LOG(WARNING)
|
||||
<< "Unable to fit offset from " << remill::LLVMThingToString(val)
|
||||
LOG(WARNING) << "Unable to fit offset from "
|
||||
<< remill::LLVMThingToString(val)
|
||||
<< " into a 64-bit signed integer";
|
||||
return false;
|
||||
}
|
||||
@@ -269,13 +267,13 @@ static bool TryCombineOffsets(uint64_t lhs_offset, OpType op_type,
|
||||
int64_t signed_result = 0;
|
||||
switch (op_type) {
|
||||
case OpType::Plus:
|
||||
signed_result = static_cast<int64_t>(lhs_offset) +
|
||||
static_cast<int64_t>(rhs_offset);
|
||||
signed_result =
|
||||
static_cast<int64_t>(lhs_offset) + static_cast<int64_t>(rhs_offset);
|
||||
break;
|
||||
|
||||
case OpType::Minus:
|
||||
signed_result = static_cast<int64_t>(lhs_offset) -
|
||||
static_cast<int64_t>(rhs_offset);
|
||||
signed_result =
|
||||
static_cast<int64_t>(lhs_offset) - static_cast<int64_t>(rhs_offset);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -329,8 +327,8 @@ struct ForwardAliasVisitor
|
||||
InstToOffset &state_access_offset_,
|
||||
llvm::LLVMContext &context);
|
||||
|
||||
bool Analyze(const remill::Arch *arch,
|
||||
KillCounter &stats, llvm::Function *func);
|
||||
bool Analyze(const remill::Arch *arch, KillCounter &stats,
|
||||
llvm::Function *func);
|
||||
|
||||
protected:
|
||||
friend class llvm::InstVisitor<ForwardAliasVisitor, VisitResult>;
|
||||
@@ -358,7 +356,6 @@ struct ForwardAliasVisitor
|
||||
virtual VisitResult visitBinaryOp_(llvm::BinaryOperator &inst, OpType op);
|
||||
|
||||
public:
|
||||
|
||||
const llvm::DataLayout dl;
|
||||
const std::vector<StateSlot> &offset_to_slot;
|
||||
ValueToOffset state_offset;
|
||||
@@ -374,9 +371,9 @@ struct ForwardAliasVisitor
|
||||
};
|
||||
|
||||
// Stream a slot of the DOT digraph.
|
||||
static void StreamSlot(
|
||||
const remill::Arch *arch, llvm::LLVMContext &context, std::ostream &dot,
|
||||
const StateSlot &slot, uint64_t access_size) {
|
||||
static void StreamSlot(const remill::Arch *arch, llvm::LLVMContext &context,
|
||||
std::ostream &dot, const StateSlot &slot,
|
||||
uint64_t access_size) {
|
||||
if (auto reg = arch->RegisterAtStateOffset(slot.offset)) {
|
||||
auto enc_reg = reg->EnclosingRegisterOfSize(access_size);
|
||||
if (!enc_reg) {
|
||||
@@ -443,8 +440,7 @@ void ForwardAliasVisitor::CreateDOTDigraph(const remill::Arch *arch,
|
||||
|
||||
std::ofstream dot(fname.str());
|
||||
dot << "digraph {" << std::endl
|
||||
<< "node [shape=none margin=0 nojustify=false labeljust=l]"
|
||||
<< std::endl;
|
||||
<< "node [shape=none margin=0 nojustify=false labeljust=l]" << std::endl;
|
||||
|
||||
// Stream node information for each block.
|
||||
for (auto &block_ref : *func) {
|
||||
@@ -472,8 +468,7 @@ void ForwardAliasVisitor::CreateDOTDigraph(const remill::Arch *arch,
|
||||
} else if (llvm::isa<llvm::StoreInst>(&inst)) {
|
||||
inst_size = dl.getTypeAllocSize(inst.getOperand(0)->getType());
|
||||
} else {
|
||||
LOG(FATAL)
|
||||
<< "Instruction " << LLVMThingToString(&inst)
|
||||
LOG(FATAL) << "Instruction " << LLVMThingToString(&inst)
|
||||
<< " has scope meta-data";
|
||||
}
|
||||
dot << "<td>" << offset << "</td><td>";
|
||||
@@ -534,10 +529,8 @@ void ForwardAliasVisitor::CreateDOTDigraph(const remill::Arch *arch,
|
||||
}
|
||||
|
||||
ForwardAliasVisitor::ForwardAliasVisitor(
|
||||
const llvm::DataLayout &dl_,
|
||||
const std::vector<StateSlot> &offset_to_slot_,
|
||||
InstToLiveSet &live_args_,
|
||||
InstToOffset &state_access_offset_,
|
||||
const llvm::DataLayout &dl_, const std::vector<StateSlot> &offset_to_slot_,
|
||||
InstToLiveSet &live_args_, InstToOffset &state_access_offset_,
|
||||
llvm::LLVMContext &context)
|
||||
: dl(dl_),
|
||||
offset_to_slot(offset_to_slot_),
|
||||
@@ -586,8 +579,8 @@ void ForwardAliasVisitor::AddInstruction(llvm::Instruction *inst) {
|
||||
// are not yet in `state_offset`) is withheld to the next analysis round
|
||||
// in the next worklist. Analysis repeats until the current worklist is
|
||||
// empty or until an error condition is hit.
|
||||
bool ForwardAliasVisitor::Analyze(const remill::Arch *arch,
|
||||
KillCounter &stats, llvm::Function *func) {
|
||||
bool ForwardAliasVisitor::Analyze(const remill::Arch *arch, KillCounter &stats,
|
||||
llvm::Function *func) {
|
||||
curr_wl.clear();
|
||||
exclude.clear();
|
||||
calls.clear();
|
||||
@@ -600,8 +593,7 @@ bool ForwardAliasVisitor::Analyze(const remill::Arch *arch,
|
||||
auto memory_ptr = LoadMemoryPointerArg(func);
|
||||
auto pc = LoadProgramCounterArg(func);
|
||||
if (!state_ptr || !memory_ptr || !pc) {
|
||||
LOG(ERROR)
|
||||
<< "Not analyzing " << func->getName().str()
|
||||
LOG(ERROR) << "Not analyzing " << func->getName().str()
|
||||
<< " for dead loads or stores";
|
||||
return false;
|
||||
}
|
||||
@@ -636,16 +628,10 @@ bool ForwardAliasVisitor::Analyze(const remill::Arch *arch,
|
||||
order_of_progress.push_back(inst);
|
||||
progress = true;
|
||||
break;
|
||||
case VisitResult::Incomplete:
|
||||
pending_wl.push_back(inst);
|
||||
break;
|
||||
case VisitResult::NoProgress:
|
||||
next_wl.push_back(inst);
|
||||
break;
|
||||
case VisitResult::Ignored:
|
||||
break;
|
||||
case VisitResult::Error:
|
||||
return false;
|
||||
case VisitResult::Incomplete: pending_wl.push_back(inst); break;
|
||||
case VisitResult::NoProgress: next_wl.push_back(inst); break;
|
||||
case VisitResult::Ignored: break;
|
||||
case VisitResult::Error: return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,8 +642,8 @@ bool ForwardAliasVisitor::Analyze(const remill::Arch *arch,
|
||||
pending_wl.clear();
|
||||
}
|
||||
|
||||
order_of_progress.insert(order_of_progress.end(),
|
||||
curr_wl.begin(), curr_wl.end());
|
||||
order_of_progress.insert(order_of_progress.end(), curr_wl.begin(),
|
||||
curr_wl.end());
|
||||
|
||||
CHECK(num_insts == order_of_progress.size());
|
||||
|
||||
@@ -669,18 +655,11 @@ bool ForwardAliasVisitor::Analyze(const remill::Arch *arch,
|
||||
// Do one final pass through, in the order in which progress was made.
|
||||
for (auto inst : order_of_progress) {
|
||||
switch (visit(inst)) {
|
||||
case VisitResult::Progress:
|
||||
break;
|
||||
case VisitResult::Incomplete:
|
||||
pending_wl.push_back(inst);
|
||||
break;
|
||||
case VisitResult::NoProgress:
|
||||
next_wl.push_back(inst);
|
||||
break;
|
||||
case VisitResult::Ignored:
|
||||
break;
|
||||
case VisitResult::Error:
|
||||
return false;
|
||||
case VisitResult::Progress: break;
|
||||
case VisitResult::Incomplete: pending_wl.push_back(inst); break;
|
||||
case VisitResult::NoProgress: next_wl.push_back(inst); break;
|
||||
case VisitResult::Ignored: break;
|
||||
case VisitResult::Error: return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -698,8 +677,7 @@ bool ForwardAliasVisitor::Analyze(const remill::Arch *arch,
|
||||
if (!pending_wl.empty()) {
|
||||
stats.failed_funcs++;
|
||||
|
||||
DLOG(WARNING)
|
||||
<< "Alias analysis failed to complete on function `"
|
||||
DLOG(WARNING) << "Alias analysis failed to complete on function `"
|
||||
<< func->getName().str() << "` with " << next_wl.size()
|
||||
<< " instructions in the worklist and " << pending_wl.size()
|
||||
<< " incomplete but no progress made in the last"
|
||||
@@ -843,8 +821,8 @@ VisitResult ForwardAliasVisitor::visitStoreInst(llvm::StoreInst &inst) {
|
||||
}
|
||||
|
||||
// Visit a `getelementptr` (GEP) instruction and update the offset map.
|
||||
VisitResult ForwardAliasVisitor::visitGetElementPtrInst(
|
||||
llvm::GetElementPtrInst &inst) {
|
||||
VisitResult
|
||||
ForwardAliasVisitor::visitGetElementPtrInst(llvm::GetElementPtrInst &inst) {
|
||||
|
||||
auto val = inst.getPointerOperand();
|
||||
|
||||
@@ -859,8 +837,7 @@ VisitResult ForwardAliasVisitor::visitGetElementPtrInst(
|
||||
}
|
||||
|
||||
// Try to get the offset as a single constant. If we can't then
|
||||
llvm::APInt const_offset(
|
||||
dl.getPointerSizeInBits(0), 0, true);
|
||||
llvm::APInt const_offset(dl.getPointerSizeInBits(0), 0, true);
|
||||
if (!inst.accumulateConstantOffset(dl, const_offset)) {
|
||||
return VisitResult::Error;
|
||||
}
|
||||
@@ -871,11 +848,11 @@ VisitResult ForwardAliasVisitor::visitGetElementPtrInst(
|
||||
static_cast<uint64_t>(const_offset.getSExtValue()),
|
||||
offset_to_slot.size(), &offset)) {
|
||||
|
||||
LOG(WARNING)
|
||||
<< "Out of bounds GEP operation: " << LLVMThingToString(&inst)
|
||||
LOG(WARNING) << "Out of bounds GEP operation: " << LLVMThingToString(&inst)
|
||||
<< " on base " << LLVMThingToString(val)
|
||||
<< " with inferred offset " << static_cast<int64_t>(offset)
|
||||
<< " (" << ptr->second << " + " << const_offset.getSExtValue() << ")"
|
||||
<< " (" << ptr->second << " + " << const_offset.getSExtValue()
|
||||
<< ")"
|
||||
<< " and max allowed offset of " << offset_to_slot.size();
|
||||
return VisitResult::Error;
|
||||
}
|
||||
@@ -914,8 +891,8 @@ VisitResult ForwardAliasVisitor::visitSub(llvm::BinaryOperator &inst) {
|
||||
}
|
||||
|
||||
// Visit an `add` or `sub` instruction.
|
||||
VisitResult ForwardAliasVisitor::visitBinaryOp_(
|
||||
llvm::BinaryOperator &inst, OpType op) {
|
||||
VisitResult ForwardAliasVisitor::visitBinaryOp_(llvm::BinaryOperator &inst,
|
||||
OpType op) {
|
||||
|
||||
auto lhs_val = inst.getOperand(0);
|
||||
auto rhs_val = inst.getOperand(1);
|
||||
@@ -982,18 +959,15 @@ VisitResult ForwardAliasVisitor::visitBinaryOp_(
|
||||
}
|
||||
|
||||
if (2 == num_offsets) {
|
||||
LOG(WARNING)
|
||||
<< "Adding or subtracting two state-pointer derived pointers";
|
||||
LOG(WARNING) << "Adding or subtracting two state-pointer derived pointers";
|
||||
return VisitResult::Error;
|
||||
|
||||
} else if (2 == (num_offsets + num_consts)) {
|
||||
uint64_t offset = 0;
|
||||
if (!TryCombineOffsets(lhs_offset, op, rhs_offset, offset_to_slot.size(),
|
||||
&offset)) {
|
||||
LOG(WARNING)
|
||||
<< "Out of bounds operation `"
|
||||
<< LLVMThingToString(&inst) << "` with LHS offset "
|
||||
<< static_cast<int64_t>(lhs_offset)
|
||||
LOG(WARNING) << "Out of bounds operation `" << LLVMThingToString(&inst)
|
||||
<< "` with LHS offset " << static_cast<int64_t>(lhs_offset)
|
||||
<< ", RHS offset " << static_cast<int64_t>(rhs_offset)
|
||||
<< ", combined offset " << static_cast<int64_t>(offset)
|
||||
<< ", and max allowed offset of " << offset_to_slot.size();
|
||||
@@ -1017,10 +991,9 @@ VisitResult ForwardAliasVisitor::visitSelect(llvm::SelectInst &inst) {
|
||||
auto false_val = inst.getFalseValue();
|
||||
auto true_ptr = state_offset.find(true_val);
|
||||
auto false_ptr = state_offset.find(false_val);
|
||||
auto in_exclude_set = exclude.count(true_val) ||
|
||||
exclude.count(false_val);
|
||||
auto in_state_offset = true_ptr != state_offset.end() ||
|
||||
false_ptr != state_offset.end();
|
||||
auto in_exclude_set = exclude.count(true_val) || exclude.count(false_val);
|
||||
auto in_state_offset =
|
||||
true_ptr != state_offset.end() || false_ptr != state_offset.end();
|
||||
|
||||
// Fail if the two values are inconsistent.
|
||||
if (in_state_offset && in_exclude_set) {
|
||||
@@ -1122,8 +1095,8 @@ VisitResult ForwardAliasVisitor::visitPHINode(llvm::PHINode &inst) {
|
||||
}
|
||||
}
|
||||
|
||||
auto complete = (num_in_state_offset + num_in_exclude_set + num_consts) ==
|
||||
num_vals;
|
||||
auto complete =
|
||||
(num_in_state_offset + num_in_exclude_set + num_consts) == num_vals;
|
||||
|
||||
// Fail if some operands are excluded and others are state offsets.
|
||||
if (num_in_state_offset && num_in_exclude_set) {
|
||||
@@ -1168,8 +1141,7 @@ VisitResult ForwardAliasVisitor::visitCallInst(llvm::CallInst &inst) {
|
||||
name.startswith("__remill_read_memory_") ||
|
||||
name.startswith("__remill_write_memory_") ||
|
||||
name == "__remill_fpu_exception_test_and_clear" ||
|
||||
name == "__mcsema_pc_tracer" ||
|
||||
name == "__mcsema_reg_tracer" ||
|
||||
name == "__mcsema_pc_tracer" || name == "__mcsema_reg_tracer" ||
|
||||
name == "__mcsema_printf") {
|
||||
|
||||
// Don't let this affect anything.
|
||||
@@ -1229,8 +1201,7 @@ class LiveSetBlockVisitor {
|
||||
std::vector<llvm::Instruction *> to_remove;
|
||||
const llvm::Function *bb_func;
|
||||
|
||||
LiveSetBlockVisitor(llvm::Module &module_,
|
||||
const InstToLiveSet &live_args_,
|
||||
LiveSetBlockVisitor(llvm::Module &module_, const InstToLiveSet &live_args_,
|
||||
InstToOffset &state_access_offset_,
|
||||
const std::vector<StateSlot> &state_slots_,
|
||||
const llvm::Function *bb_func_,
|
||||
@@ -1240,8 +1211,8 @@ class LiveSetBlockVisitor {
|
||||
void CollectDeadInsts(KillCounter &stats);
|
||||
bool VisitBlock(llvm::BasicBlock *block, KillCounter &stats);
|
||||
bool DeleteDeadInsts(KillCounter &stats);
|
||||
void CreateDOTDigraph(const remill::Arch *,
|
||||
llvm::Function *func, const char *extensions);
|
||||
void CreateDOTDigraph(const remill::Arch *, llvm::Function *func,
|
||||
const char *extensions);
|
||||
|
||||
private:
|
||||
bool on_remove_pass;
|
||||
@@ -1249,11 +1220,9 @@ class LiveSetBlockVisitor {
|
||||
};
|
||||
|
||||
LiveSetBlockVisitor::LiveSetBlockVisitor(
|
||||
llvm::Module &module_,
|
||||
const InstToLiveSet &live_args_,
|
||||
llvm::Module &module_, const InstToLiveSet &live_args_,
|
||||
InstToOffset &state_access_offset_,
|
||||
const std::vector<StateSlot> &state_slots_,
|
||||
const llvm::Function *bb_func_,
|
||||
const std::vector<StateSlot> &state_slots_, const llvm::Function *bb_func_,
|
||||
const llvm::DataLayout *dl_)
|
||||
: module(module_),
|
||||
live_args(live_args_),
|
||||
@@ -1477,8 +1446,7 @@ void LiveSetBlockVisitor::CreateDOTDigraph(const remill::Arch *arch,
|
||||
|
||||
std::ofstream dot(fname.str());
|
||||
dot << "digraph {" << std::endl
|
||||
<< "node [shape=none margin=0 nojustify=false labeljust=l]"
|
||||
<< std::endl;
|
||||
<< "node [shape=none margin=0 nojustify=false labeljust=l]" << std::endl;
|
||||
|
||||
// Figure out relevant load/stores to print.
|
||||
LiveSet used;
|
||||
@@ -1545,6 +1513,7 @@ void LiveSetBlockVisitor::CreateDOTDigraph(const remill::Arch *arch,
|
||||
|
||||
// Then print out one row per instruction.
|
||||
for (auto &inst : *block) {
|
||||
|
||||
// First row, print out the DEAD slots on entry.
|
||||
if (debug_live_args_at_call.count(&inst)) {
|
||||
const auto &clive = debug_live_args_at_call[&inst];
|
||||
@@ -1571,16 +1540,14 @@ void LiveSetBlockVisitor::CreateDOTDigraph(const remill::Arch *arch,
|
||||
} else if (llvm::isa<llvm::StoreInst>(&inst)) {
|
||||
inst_size = dl->getTypeAllocSize(inst.getOperand(0)->getType());
|
||||
} else {
|
||||
LOG(FATAL)
|
||||
<< "Instruction " << LLVMThingToString(&inst)
|
||||
LOG(FATAL) << "Instruction " << LLVMThingToString(&inst)
|
||||
<< " has scope meta-data";
|
||||
}
|
||||
|
||||
StreamSlot(arch, context, dot, slot, inst_size);
|
||||
|
||||
// slot size minus load/store size
|
||||
dot << "</td><td align=\"left\">" << (slot.size - inst_size)
|
||||
<< "</td>";
|
||||
dot << "</td><td align=\"left\">" << (slot.size - inst_size) << "</td>";
|
||||
} else {
|
||||
dot << "</td><td></td>";
|
||||
}
|
||||
@@ -1637,8 +1604,7 @@ class ForwardingBlockVisitor {
|
||||
const InstToLiveSet &live_args;
|
||||
const llvm::FunctionType *lifted_func_ty;
|
||||
|
||||
ForwardingBlockVisitor(
|
||||
llvm::Function &func_,
|
||||
ForwardingBlockVisitor(llvm::Function &func_,
|
||||
llvm::DominatorTree &dominator_tree_,
|
||||
InstToOffset &state_access_offset_,
|
||||
const std::vector<StateSlot> &state_slots_,
|
||||
@@ -1654,11 +1620,9 @@ class ForwardingBlockVisitor {
|
||||
};
|
||||
|
||||
ForwardingBlockVisitor::ForwardingBlockVisitor(
|
||||
llvm::Function &func_,
|
||||
llvm::DominatorTree &dominator_tree_,
|
||||
llvm::Function &func_, llvm::DominatorTree &dominator_tree_,
|
||||
InstToOffset &state_access_offset_,
|
||||
const std::vector<StateSlot> &state_slots_,
|
||||
const InstToLiveSet &live_args_,
|
||||
const std::vector<StateSlot> &state_slots_, const InstToLiveSet &live_args_,
|
||||
const llvm::DataLayout *dl_)
|
||||
: func(func_),
|
||||
dominator_tree(dominator_tree_),
|
||||
@@ -1670,56 +1634,51 @@ ForwardingBlockVisitor::ForwardingBlockVisitor(
|
||||
|
||||
void ForwardingBlockVisitor::Visit(const ValueToOffset &val_to_offset,
|
||||
KillCounter &stats) {
|
||||
|
||||
// If any visit makes progress, continue the loop.
|
||||
for (auto &block : func) {
|
||||
VisitBlock(&block, val_to_offset, stats);
|
||||
}
|
||||
}
|
||||
|
||||
static llvm::Value *ConvertToSameSizedType(
|
||||
llvm::Value *val, llvm::Type *dest_type, llvm::Instruction *insert_loc) {
|
||||
static llvm::Value *ConvertToSameSizedType(llvm::Value *val,
|
||||
llvm::Type *dest_type,
|
||||
llvm::Instruction *insert_loc) {
|
||||
auto empty_name = llvm::Twine::createNull();
|
||||
auto val_type = val->getType();
|
||||
if (val_type->isIntegerTy()) {
|
||||
if (dest_type->isPointerTy()) {
|
||||
return new llvm::IntToPtrInst(
|
||||
val, dest_type, empty_name, insert_loc);
|
||||
return new llvm::IntToPtrInst(val, dest_type, empty_name, insert_loc);
|
||||
} else {
|
||||
return new llvm::BitCastInst(val, dest_type, empty_name, insert_loc);
|
||||
}
|
||||
|
||||
} else if (val_type->isFloatingPointTy()) {
|
||||
if (dest_type->isPointerTy()) {
|
||||
LOG(ERROR)
|
||||
<< "Likely nonsensical forwarding of float type "
|
||||
LOG(ERROR) << "Likely nonsensical forwarding of float type "
|
||||
<< LLVMThingToString(val_type) << " to pointer type "
|
||||
<< LLVMThingToString(dest_type);
|
||||
|
||||
return nullptr;
|
||||
} else {
|
||||
return new llvm::BitCastInst(
|
||||
val, dest_type, empty_name, insert_loc);
|
||||
return new llvm::BitCastInst(val, dest_type, empty_name, insert_loc);
|
||||
}
|
||||
|
||||
} else if (val_type->isPointerTy()) {
|
||||
if (dest_type->isIntegerTy()) {
|
||||
return new llvm::PtrToIntInst(
|
||||
val, dest_type, empty_name, insert_loc);
|
||||
return new llvm::PtrToIntInst(val, dest_type, empty_name, insert_loc);
|
||||
|
||||
} else if (dest_type->isPointerTy()) {
|
||||
return new llvm::BitCastInst(
|
||||
val, dest_type, empty_name, insert_loc);
|
||||
return new llvm::BitCastInst(val, dest_type, empty_name, insert_loc);
|
||||
|
||||
} else {
|
||||
LOG(ERROR)
|
||||
<< "Likely nonsensical forwarding of pointer type "
|
||||
LOG(ERROR) << "Likely nonsensical forwarding of pointer type "
|
||||
<< LLVMThingToString(val_type) << " to type "
|
||||
<< LLVMThingToString(dest_type);
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
return new llvm::BitCastInst(
|
||||
val, dest_type, empty_name, insert_loc);
|
||||
return new llvm::BitCastInst(val, dest_type, empty_name, insert_loc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1737,8 +1696,7 @@ void ForwardingBlockVisitor::VisitBlock(llvm::BasicBlock *block,
|
||||
}
|
||||
|
||||
for (auto inst : insts) {
|
||||
if (llvm::isa<llvm::CallInst>(inst) ||
|
||||
llvm::isa<llvm::InvokeInst>(inst)) {
|
||||
if (llvm::isa<llvm::CallInst>(inst) || llvm::isa<llvm::InvokeInst>(inst)) {
|
||||
|
||||
auto live_args_it = live_args.find(inst);
|
||||
if (live_args_it == live_args.end()) {
|
||||
@@ -1812,16 +1770,16 @@ void ForwardingBlockVisitor::VisitBlock(llvm::BasicBlock *block,
|
||||
// Forwarding, but changing the size.
|
||||
} else if (next_size < val_size) {
|
||||
if (val_type->isIntegerTy() && next_type->isIntegerTy()) {
|
||||
auto trunc = new llvm::TruncInst(
|
||||
val, next_type, empty_name, next_load);
|
||||
auto trunc =
|
||||
new llvm::TruncInst(val, next_type, empty_name, next_load);
|
||||
next_load->replaceAllUsesWith(trunc);
|
||||
next_load->eraseFromParent();
|
||||
state_access_offset.erase(next_load);
|
||||
|
||||
} else if (val_type->isFloatingPointTy() &&
|
||||
next_type->isFloatingPointTy()) {
|
||||
auto trunc = new llvm::FPTruncInst(
|
||||
val, next_type, empty_name, next_load);
|
||||
auto trunc =
|
||||
new llvm::FPTruncInst(val, next_type, empty_name, next_load);
|
||||
next_load->replaceAllUsesWith(trunc);
|
||||
next_load->eraseFromParent();
|
||||
state_access_offset.erase(next_load);
|
||||
@@ -1888,8 +1846,8 @@ void ForwardingBlockVisitor::VisitBlock(llvm::BasicBlock *block,
|
||||
|
||||
// Forwarding, but changing the type.
|
||||
} else if (val_size == next_size) {
|
||||
if (auto cast = ConvertToSameSizedType(load_inst, next_type,
|
||||
next_load)) {
|
||||
if (auto cast =
|
||||
ConvertToSameSizedType(load_inst, next_type, next_load)) {
|
||||
next_load->replaceAllUsesWith(cast);
|
||||
next_load->eraseFromParent();
|
||||
state_access_offset.erase(next_load);
|
||||
@@ -1905,16 +1863,16 @@ void ForwardingBlockVisitor::VisitBlock(llvm::BasicBlock *block,
|
||||
} else if (next_size < val_size) {
|
||||
try_truncate:
|
||||
if (val_type->isIntegerTy() && next_type->isIntegerTy()) {
|
||||
auto trunc = new llvm::TruncInst(
|
||||
load_inst, next_type, empty_name, next_load);
|
||||
auto trunc =
|
||||
new llvm::TruncInst(load_inst, next_type, empty_name, next_load);
|
||||
next_load->replaceAllUsesWith(trunc);
|
||||
next_load->eraseFromParent();
|
||||
state_access_offset.erase(next_load);
|
||||
|
||||
} else if (val_type->isFloatingPointTy() &&
|
||||
next_type->isFloatingPointTy()) {
|
||||
auto trunc = new llvm::FPTruncInst(
|
||||
load_inst, next_type, empty_name, next_load);
|
||||
auto trunc = new llvm::FPTruncInst(load_inst, next_type, empty_name,
|
||||
next_load);
|
||||
next_load->replaceAllUsesWith(trunc);
|
||||
next_load->eraseFromParent();
|
||||
state_access_offset.erase(next_load);
|
||||
@@ -1953,8 +1911,7 @@ std::vector<StateSlot> StateSlots(const remill::Arch *arch,
|
||||
if (!FLAGS_dot_output_dir.empty()) {
|
||||
if (!TryCreateDirectory(FLAGS_dot_output_dir)) {
|
||||
FLAGS_dot_output_dir.clear();
|
||||
LOG(ERROR)
|
||||
<< "Invalid path specified to `--dot_output_dir`.";
|
||||
LOG(ERROR) << "Invalid path specified to `--dot_output_dir`.";
|
||||
} else {
|
||||
FLAGS_dot_output_dir = CanonicalPath(FLAGS_dot_output_dir);
|
||||
}
|
||||
@@ -1975,8 +1932,7 @@ std::vector<StateSlot> StateSlots(const remill::Arch *arch,
|
||||
|
||||
// Analyze a module, discover aliasing loads and stores, and remove dead
|
||||
// stores into the `State` structure.
|
||||
void RemoveDeadStores(const remill::Arch *arch,
|
||||
llvm::Module *module,
|
||||
void RemoveDeadStores(const remill::Arch *arch, llvm::Module *module,
|
||||
llvm::Function *bb_func,
|
||||
const std::vector<StateSlot> &slots,
|
||||
llvm::Function *ds_func) {
|
||||
@@ -2002,8 +1958,7 @@ void RemoveDeadStores(const remill::Arch *arch,
|
||||
continue;
|
||||
}
|
||||
|
||||
ForwardAliasVisitor fav(
|
||||
dl, slots, live_args, state_access_offset,
|
||||
ForwardAliasVisitor fav(dl, slots, live_args, state_access_offset,
|
||||
func.getContext());
|
||||
|
||||
// If the analysis succeeds for this function, then do store-to-load
|
||||
@@ -2015,16 +1970,16 @@ void RemoveDeadStores(const remill::Arch *arch,
|
||||
|
||||
if (!FLAGS_disable_register_forwarding) {
|
||||
llvm::DominatorTree dominator_tree(func);
|
||||
ForwardingBlockVisitor fbv(
|
||||
func, dominator_tree, state_access_offset, slots, live_args, &dl);
|
||||
ForwardingBlockVisitor fbv(func, dominator_tree, state_access_offset,
|
||||
slots, live_args, &dl);
|
||||
fbv.Visit(fav.state_offset, stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform live set analysis
|
||||
LiveSetBlockVisitor visitor(*module, live_args, state_access_offset,
|
||||
slots, bb_func, &dl);
|
||||
LiveSetBlockVisitor visitor(*module, live_args, state_access_offset, slots,
|
||||
bb_func, &dl);
|
||||
|
||||
visitor.FindLiveInsts(stats);
|
||||
visitor.CollectDeadInsts(stats);
|
||||
|
||||
@@ -16,7 +16,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
class Function;
|
||||
class Module;
|
||||
} // namespace llvm
|
||||
namespace remill {
|
||||
@@ -52,8 +56,9 @@ std::vector<StateSlot> StateSlots(const remill::Arch *arch,
|
||||
|
||||
// Analyze a module, discover aliasing loads and stores, and remove dead
|
||||
// stores into the `State` structure.
|
||||
void RemoveDeadStores(
|
||||
const remill::Arch *arch, llvm::Module *module, llvm::Function *bb_func,
|
||||
const std::vector<StateSlot> &slots, llvm::Function *ds_func=nullptr);
|
||||
void RemoveDeadStores(const remill::Arch *arch, llvm::Module *module,
|
||||
llvm::Function *bb_func,
|
||||
const std::vector<StateSlot> &slots,
|
||||
llvm::Function *ds_func = nullptr);
|
||||
|
||||
} // namespace remill
|
||||
|
||||
@@ -14,27 +14,25 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "remill/BC/IntrinsicTable.h"
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <llvm/IR/Constants.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
|
||||
#include "remill/BC/IntrinsicTable.h"
|
||||
#include <vector>
|
||||
|
||||
#include "remill/BC/Util.h"
|
||||
|
||||
namespace remill {
|
||||
namespace {
|
||||
|
||||
// Find a specific function.
|
||||
static llvm::Function *FindIntrinsic(llvm::Module *module,
|
||||
const char *name) {
|
||||
static llvm::Function *FindIntrinsic(llvm::Module *module, const char *name) {
|
||||
auto function = FindFunction(module, name);
|
||||
CHECK(nullptr != function)
|
||||
<< "Unable to find intrinsic: " << name;
|
||||
CHECK(nullptr != function) << "Unable to find intrinsic: " << name;
|
||||
|
||||
// We don't want calls to memory intrinsics to be duplicated because then
|
||||
// they might have the wrong side effects!
|
||||
@@ -70,14 +68,12 @@ IntrinsicTable::IntrinsicTable(llvm::Module *module)
|
||||
|
||||
// Control-flow.
|
||||
function_call(FindIntrinsic(module, "__remill_function_call")),
|
||||
function_return(FindIntrinsic(
|
||||
module, "__remill_function_return")),
|
||||
function_return(FindIntrinsic(module, "__remill_function_return")),
|
||||
jump(FindIntrinsic(module, "__remill_jump")),
|
||||
missing_block(FindIntrinsic(module, "__remill_missing_block")),
|
||||
|
||||
// OS interaction.
|
||||
async_hyper_call(FindIntrinsic(
|
||||
module, "__remill_async_hyper_call")),
|
||||
async_hyper_call(FindIntrinsic(module, "__remill_async_hyper_call")),
|
||||
|
||||
// Memory access.
|
||||
read_memory_8(FindPureIntrinsic(module, "__remill_read_memory_8")),
|
||||
@@ -97,20 +93,19 @@ IntrinsicTable::IntrinsicTable(llvm::Module *module)
|
||||
|
||||
write_memory_f32(FindPureIntrinsic(module, "__remill_write_memory_f32")),
|
||||
write_memory_f64(FindPureIntrinsic(module, "__remill_write_memory_f64")),
|
||||
write_memory_f80(FindPureIntrinsic(
|
||||
module, "__remill_write_memory_f80")),
|
||||
write_memory_f128(FindPureIntrinsic(
|
||||
module, "__remill_write_memory_f128")),
|
||||
write_memory_f80(FindPureIntrinsic(module, "__remill_write_memory_f80")),
|
||||
write_memory_f128(
|
||||
FindPureIntrinsic(module, "__remill_write_memory_f128")),
|
||||
|
||||
// Memory barriers.
|
||||
barrier_load_load(FindPureIntrinsic(
|
||||
module, "__remill_barrier_load_load")),
|
||||
barrier_load_store(FindPureIntrinsic(
|
||||
module, "__remill_barrier_load_store")),
|
||||
barrier_store_load(FindPureIntrinsic(
|
||||
module, "__remill_barrier_store_load")),
|
||||
barrier_store_store(FindPureIntrinsic(
|
||||
module, "__remill_barrier_store_store")),
|
||||
barrier_load_load(
|
||||
FindPureIntrinsic(module, "__remill_barrier_load_load")),
|
||||
barrier_load_store(
|
||||
FindPureIntrinsic(module, "__remill_barrier_load_store")),
|
||||
barrier_store_load(
|
||||
FindPureIntrinsic(module, "__remill_barrier_store_load")),
|
||||
barrier_store_store(
|
||||
FindPureIntrinsic(module, "__remill_barrier_store_store")),
|
||||
atomic_begin(FindPureIntrinsic(module, "__remill_atomic_begin")),
|
||||
atomic_end(FindPureIntrinsic(module, "__remill_atomic_end")),
|
||||
delay_slot_begin(FindPureIntrinsic(module, "__remill_delay_slot_begin")),
|
||||
|
||||
+131
-161
@@ -14,48 +14,43 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "remill/BC/Lifter.h"
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <functional>
|
||||
#include <ios>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <llvm/ADT/SmallVector.h>
|
||||
|
||||
#include <llvm/IR/BasicBlock.h>
|
||||
#include <llvm/IR/Constants.h>
|
||||
#include <llvm/IR/DataLayout.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/IntrinsicInst.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/LegacyPassManager.h>
|
||||
#include <llvm/IR/Metadata.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Operator.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
|
||||
#include <llvm/Transforms/Scalar.h>
|
||||
#include <llvm/Transforms/Utils/Cloning.h>
|
||||
#include <llvm/Transforms/Utils/ValueMapper.h>
|
||||
|
||||
#include <functional>
|
||||
#include <ios>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "remill/Arch/Arch.h"
|
||||
#include "remill/Arch/Instruction.h"
|
||||
#include "remill/Arch/Name.h"
|
||||
|
||||
#include "remill/BC/ABI.h"
|
||||
#include "remill/BC/Compat/DataLayout.h"
|
||||
#include "remill/BC/IntrinsicTable.h"
|
||||
#include "remill/BC/Lifter.h"
|
||||
#include "remill/BC/Util.h"
|
||||
|
||||
#include "remill/OS/OS.h"
|
||||
|
||||
namespace remill {
|
||||
@@ -74,10 +69,9 @@ llvm::Function *GetInstructionFunction(llvm::Module *module,
|
||||
}
|
||||
|
||||
if (!isel->isConstant() || !isel->hasInitializer()) {
|
||||
LOG(FATAL)
|
||||
<< "Expected a `constexpr` variable as the function pointer for "
|
||||
<< "instruction semantic function " << function
|
||||
<< ": " << LLVMThingToString(isel);
|
||||
LOG(FATAL) << "Expected a `constexpr` variable as the function pointer for "
|
||||
<< "instruction semantic function " << function << ": "
|
||||
<< LLVMThingToString(isel);
|
||||
}
|
||||
|
||||
auto sem = isel->getInitializer()->stripPointerCasts();
|
||||
@@ -92,14 +86,14 @@ InstructionLifter::InstructionLifter(const Arch *arch_,
|
||||
const IntrinsicTable *intrinsics_)
|
||||
: arch(arch_),
|
||||
word_type(llvm::Type::getIntNTy(
|
||||
intrinsics_->async_hyper_call->getContext(),
|
||||
arch->address_size)),
|
||||
intrinsics_->async_hyper_call->getContext(), arch->address_size)),
|
||||
intrinsics(intrinsics_),
|
||||
last_func(nullptr) {}
|
||||
|
||||
// Lift a single instruction into a basic block.
|
||||
LiftStatus InstructionLifter::LiftIntoBlock(
|
||||
Instruction &arch_inst, llvm::BasicBlock *block, bool is_delayed) {
|
||||
LiftStatus InstructionLifter::LiftIntoBlock(Instruction &arch_inst,
|
||||
llvm::BasicBlock *block,
|
||||
bool is_delayed) {
|
||||
|
||||
llvm::Function *const func = block->getParent();
|
||||
llvm::Module *const module = func->getParent();
|
||||
@@ -114,21 +108,18 @@ LiftStatus InstructionLifter::LiftIntoBlock(
|
||||
if (arch_inst.IsValid()) {
|
||||
isel_func = GetInstructionFunction(module, arch_inst.function);
|
||||
} else {
|
||||
LOG(ERROR)
|
||||
<< "Cannot decode instruction bytes at "
|
||||
<< std::hex << arch_inst.pc << std::dec;
|
||||
LOG(ERROR) << "Cannot decode instruction bytes at " << std::hex
|
||||
<< arch_inst.pc << std::dec;
|
||||
|
||||
isel_func = GetInstructionFunction(module, "INVALID_INSTRUCTION");
|
||||
CHECK(isel_func != nullptr)
|
||||
<< "INVALID_INSTRUCTION doesn't exist.";
|
||||
CHECK(isel_func != nullptr) << "INVALID_INSTRUCTION doesn't exist.";
|
||||
|
||||
arch_inst.operands.clear();
|
||||
status = kLiftedInvalidInstruction;
|
||||
}
|
||||
|
||||
if (!isel_func) {
|
||||
LOG(ERROR)
|
||||
<< "Missing semantics for instruction " << arch_inst.Serialize();
|
||||
LOG(ERROR) << "Missing semantics for instruction " << arch_inst.Serialize();
|
||||
|
||||
isel_func = GetInstructionFunction(module, "UNSUPPORTED_INSTRUCTION");
|
||||
CHECK(isel_func != nullptr)
|
||||
@@ -155,8 +146,7 @@ LiftStatus InstructionLifter::LiftIntoBlock(
|
||||
// semantics function.
|
||||
if (is_delayed) {
|
||||
llvm::Value *temp_args[] = {ir.CreateLoad(mem_ptr_ref)};
|
||||
ir.CreateStore(
|
||||
ir.CreateCall(intrinsics->delay_slot_begin, temp_args),
|
||||
ir.CreateStore(ir.CreateCall(intrinsics->delay_slot_begin, temp_args),
|
||||
mem_ptr_ref);
|
||||
|
||||
// Leave `PC` and `NEXT_PC` alone; we assume that the semantics have done
|
||||
@@ -168,8 +158,7 @@ LiftStatus InstructionLifter::LiftIntoBlock(
|
||||
// the program counter in the semantics code.
|
||||
ir.CreateStore(next_pc, pc_ref);
|
||||
ir.CreateStore(
|
||||
ir.CreateAdd(
|
||||
next_pc,
|
||||
ir.CreateAdd(next_pc,
|
||||
llvm::ConstantInt::get(word_type, arch_inst.bytes.size())),
|
||||
next_pc_ref);
|
||||
}
|
||||
@@ -177,8 +166,7 @@ LiftStatus InstructionLifter::LiftIntoBlock(
|
||||
// Begin an atomic block.
|
||||
if (arch_inst.is_atomic_read_modify_write) {
|
||||
llvm::Value *temp_args[] = {ir.CreateLoad(mem_ptr_ref)};
|
||||
ir.CreateStore(
|
||||
ir.CreateCall(intrinsics->atomic_begin, temp_args),
|
||||
ir.CreateStore(ir.CreateCall(intrinsics->atomic_begin, temp_args),
|
||||
mem_ptr_ref);
|
||||
}
|
||||
|
||||
@@ -196,9 +184,8 @@ LiftStatus InstructionLifter::LiftIntoBlock(
|
||||
for (auto &op : arch_inst.operands) {
|
||||
CHECK(arg_num < isel_func_type->getNumParams())
|
||||
<< "Function " << arch_inst.function << ", implemented by "
|
||||
<< isel_func->getName().str() << ", should have at least "
|
||||
<< arg_num << " arguments for instruction "
|
||||
<< arch_inst.Serialize();
|
||||
<< isel_func->getName().str() << ", should have at least " << arg_num
|
||||
<< " arguments for instruction " << arch_inst.Serialize();
|
||||
|
||||
auto arg = NthArgument(isel_func, arg_num);
|
||||
auto arg_type = arg->getType();
|
||||
@@ -206,8 +193,8 @@ LiftStatus InstructionLifter::LiftIntoBlock(
|
||||
arg_num += 1;
|
||||
auto op_type = operand->getType();
|
||||
CHECK(op_type == arg_type)
|
||||
<< "Lifted operand " << op.Serialize() << " to "
|
||||
<< arch_inst.function << " does not have the correct type. Expected "
|
||||
<< "Lifted operand " << op.Serialize() << " to " << arch_inst.function
|
||||
<< " does not have the correct type. Expected "
|
||||
<< LLVMThingToString(arg_type) << " but got "
|
||||
<< LLVMThingToString(op_type) << ".";
|
||||
|
||||
@@ -223,8 +210,7 @@ LiftStatus InstructionLifter::LiftIntoBlock(
|
||||
// End an atomic block.
|
||||
if (arch_inst.is_atomic_read_modify_write) {
|
||||
llvm::Value *temp_args[] = {ir.CreateLoad(mem_ptr_ref)};
|
||||
ir.CreateStore(
|
||||
ir.CreateCall(intrinsics->atomic_end, temp_args),
|
||||
ir.CreateStore(ir.CreateCall(intrinsics->atomic_end, temp_args),
|
||||
mem_ptr_ref);
|
||||
}
|
||||
|
||||
@@ -241,8 +227,7 @@ LiftStatus InstructionLifter::LiftIntoBlock(
|
||||
ir.CreateStore(next_pc, next_pc_ref);
|
||||
|
||||
llvm::Value *temp_args[] = {ir.CreateLoad(mem_ptr_ref)};
|
||||
ir.CreateStore(
|
||||
ir.CreateCall(intrinsics->delay_slot_end, temp_args),
|
||||
ir.CreateStore(ir.CreateCall(intrinsics->delay_slot_end, temp_args),
|
||||
mem_ptr_ref);
|
||||
}
|
||||
|
||||
@@ -274,8 +259,9 @@ llvm::Value *InstructionLifter::LoadRegValue(llvm::BasicBlock *block,
|
||||
}
|
||||
|
||||
// Return a register value, or zero.
|
||||
llvm::Value *InstructionLifter::LoadWordRegValOrZero(
|
||||
llvm::BasicBlock *block, const std::string ®_name,
|
||||
llvm::Value *
|
||||
InstructionLifter::LoadWordRegValOrZero(llvm::BasicBlock *block,
|
||||
const std::string ®_name,
|
||||
llvm::ConstantInt *zero) {
|
||||
|
||||
if (reg_name.empty()) {
|
||||
@@ -286,8 +272,7 @@ llvm::Value *InstructionLifter::LoadWordRegValOrZero(
|
||||
auto val_type = llvm::dyn_cast_or_null<llvm::IntegerType>(val->getType());
|
||||
auto word_type = zero->getType();
|
||||
|
||||
CHECK(val_type)
|
||||
<< "Register " << reg_name << " expected to be an integer.";
|
||||
CHECK(val_type) << "Register " << reg_name << " expected to be an integer.";
|
||||
|
||||
auto val_size = val_type->getBitWidth();
|
||||
auto word_size = word_type->getBitWidth();
|
||||
@@ -302,8 +287,9 @@ llvm::Value *InstructionLifter::LoadWordRegValOrZero(
|
||||
return val;
|
||||
}
|
||||
|
||||
llvm::Value *InstructionLifter::LiftShiftRegisterOperand(
|
||||
Instruction &inst, llvm::BasicBlock *block,
|
||||
llvm::Value *
|
||||
InstructionLifter::LiftShiftRegisterOperand(Instruction &inst,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Argument *arg, Operand &op) {
|
||||
|
||||
llvm::Function *func = block->getParent();
|
||||
@@ -334,8 +320,8 @@ llvm::Value *InstructionLifter::LiftShiftRegisterOperand(
|
||||
auto curr_size = reg_size;
|
||||
if (Operand::ShiftRegister::kExtendInvalid != op.shift_reg.extend_op) {
|
||||
|
||||
auto extract_type = llvm::Type::getIntNTy(
|
||||
context, op.shift_reg.extract_size);
|
||||
auto extract_type =
|
||||
llvm::Type::getIntNTy(context, op.shift_reg.extract_size);
|
||||
|
||||
if (reg_size > op.shift_reg.extract_size) {
|
||||
curr_size = op.shift_reg.extract_size;
|
||||
@@ -360,8 +346,7 @@ llvm::Value *InstructionLifter::LiftShiftRegisterOperand(
|
||||
curr_size = op.size;
|
||||
break;
|
||||
default:
|
||||
LOG(FATAL)
|
||||
<< "Invalid extend operation type for instruction at "
|
||||
LOG(FATAL) << "Invalid extend operation type for instruction at "
|
||||
<< std::hex << inst.pc;
|
||||
break;
|
||||
}
|
||||
@@ -383,6 +368,7 @@ llvm::Value *InstructionLifter::LiftShiftRegisterOperand(
|
||||
<< inst.Serialize();
|
||||
|
||||
switch (op.shift_reg.shift_op) {
|
||||
|
||||
// Left shift.
|
||||
case Operand::ShiftRegister::kShiftLeftWithZeroes:
|
||||
reg = ir.CreateShl(reg, shift_val);
|
||||
@@ -390,8 +376,8 @@ llvm::Value *InstructionLifter::LiftShiftRegisterOperand(
|
||||
|
||||
// Masking shift left.
|
||||
case Operand::ShiftRegister::kShiftLeftWithOnes: {
|
||||
const auto mask_val = llvm::ConstantInt::get(
|
||||
reg_type, ~((~zero) << shift_size));
|
||||
const auto mask_val =
|
||||
llvm::ConstantInt::get(reg_type, ~((~zero) << shift_size));
|
||||
reg = ir.CreateOr(ir.CreateShl(reg, shift_val), mask_val);
|
||||
break;
|
||||
}
|
||||
@@ -426,8 +412,7 @@ llvm::Value *InstructionLifter::LiftShiftRegisterOperand(
|
||||
break;
|
||||
}
|
||||
|
||||
case Operand::ShiftRegister::kShiftInvalid:
|
||||
break;
|
||||
case Operand::ShiftRegister::kShiftInvalid: break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,33 +438,28 @@ static llvm::Type *IntendedArgumentType(llvm::Argument *arg) {
|
||||
return arg->getType();
|
||||
}
|
||||
|
||||
static llvm::Value *ConvertToIntendedType(Instruction &inst, Operand &op,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Value *val,
|
||||
llvm::Type *intended_type) {
|
||||
static llvm::Value *
|
||||
ConvertToIntendedType(Instruction &inst, Operand &op, llvm::BasicBlock *block,
|
||||
llvm::Value *val, llvm::Type *intended_type) {
|
||||
auto val_type = val->getType();
|
||||
if (val->getType() == intended_type) {
|
||||
return val;
|
||||
} else if (auto val_ptr_type = llvm::dyn_cast<llvm::PointerType>(val_type)) {
|
||||
if (intended_type->isPointerTy()) {
|
||||
return new llvm::BitCastInst(
|
||||
val, intended_type, val->getName(), block);
|
||||
return new llvm::BitCastInst(val, intended_type, val->getName(), block);
|
||||
} else if (intended_type->isIntegerTy()) {
|
||||
return new llvm::PtrToIntInst(
|
||||
val, intended_type, val->getName(), block);
|
||||
return new llvm::PtrToIntInst(val, intended_type, val->getName(), block);
|
||||
}
|
||||
} else if (val_type->isFloatingPointTy()) {
|
||||
if (intended_type->isIntegerTy()) {
|
||||
return new llvm::BitCastInst(
|
||||
val, intended_type, val->getName(), block);
|
||||
return new llvm::BitCastInst(val, intended_type, val->getName(), block);
|
||||
}
|
||||
}
|
||||
|
||||
LOG(FATAL)
|
||||
<< "Unable to convert value " << LLVMThingToString(val)
|
||||
<< " to intended argument type " << LLVMThingToString(intended_type)
|
||||
<< " for operand " << op.Serialize() << " of instruction "
|
||||
<< inst.Serialize();
|
||||
LOG(FATAL) << "Unable to convert value " << LLVMThingToString(val)
|
||||
<< " to intended argument type "
|
||||
<< LLVMThingToString(intended_type) << " for operand "
|
||||
<< op.Serialize() << " of instruction " << inst.Serialize();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -490,9 +470,10 @@ static llvm::Value *ConvertToIntendedType(Instruction &inst, Operand &op,
|
||||
// for registers. In the case of write operands, the argument type is always
|
||||
// a pointer. In the case of read operands, the argument type is sometimes
|
||||
// a pointer (e.g. when passing a vector to an instruction semantics function).
|
||||
llvm::Value *InstructionLifter::LiftRegisterOperand(
|
||||
Instruction &inst, llvm::BasicBlock *block,
|
||||
llvm::Argument *arg, Operand &op) {
|
||||
llvm::Value *InstructionLifter::LiftRegisterOperand(Instruction &inst,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Argument *arg,
|
||||
Operand &op) {
|
||||
|
||||
llvm::Function *func = block->getParent();
|
||||
llvm::Module *module = func->getParent();
|
||||
@@ -570,10 +551,9 @@ llvm::Value *InstructionLifter::LiftRegisterOperand(
|
||||
}
|
||||
|
||||
// Lift an immediate operand.
|
||||
llvm::Value *InstructionLifter::LiftImmediateOperand(Instruction &inst,
|
||||
llvm::BasicBlock *,
|
||||
llvm::Argument *arg,
|
||||
Operand &arch_op) {
|
||||
llvm::Value *
|
||||
InstructionLifter::LiftImmediateOperand(Instruction &inst, llvm::BasicBlock *,
|
||||
llvm::Argument *arg, Operand &arch_op) {
|
||||
auto arg_type = arg->getType();
|
||||
if (arch_op.size > word_type->getBitWidth()) {
|
||||
CHECK(arg_type->isIntegerTy(static_cast<uint32_t>(arch_op.size)))
|
||||
@@ -587,8 +567,8 @@ llvm::Value *InstructionLifter::LiftImmediateOperand(Instruction &inst,
|
||||
<< "Operand structure encodes a truncated " << arch_op.size << " bit "
|
||||
<< "value for instruction at " << std::hex << inst.pc;
|
||||
|
||||
return llvm::ConstantInt::get(
|
||||
arg_type, arch_op.imm.val, arch_op.imm.is_signed);
|
||||
return llvm::ConstantInt::get(arg_type, arch_op.imm.val,
|
||||
arch_op.imm.is_signed);
|
||||
|
||||
} else {
|
||||
CHECK(arg_type->isIntegerTy(word_type->getBitWidth()))
|
||||
@@ -597,14 +577,16 @@ llvm::Value *InstructionLifter::LiftImmediateOperand(Instruction &inst,
|
||||
<< "smaller than the machine word size should be represented as "
|
||||
<< "machine word sized arguments to semantics functions.";
|
||||
|
||||
return llvm::ConstantInt::get(
|
||||
word_type, arch_op.imm.val, arch_op.imm.is_signed);
|
||||
return llvm::ConstantInt::get(word_type, arch_op.imm.val,
|
||||
arch_op.imm.is_signed);
|
||||
}
|
||||
}
|
||||
|
||||
// Zero-extend a value to be the machine word size.
|
||||
llvm::Value *InstructionLifter::LiftAddressOperand(
|
||||
Instruction &inst, llvm::BasicBlock *block, llvm::Argument *, Operand &op) {
|
||||
llvm::Value *InstructionLifter::LiftAddressOperand(Instruction &inst,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Argument *,
|
||||
Operand &op) {
|
||||
auto &arch_addr = op.addr;
|
||||
auto zero = llvm::ConstantInt::get(word_type, 0, false);
|
||||
auto word_size = word_type->getBitWidth();
|
||||
@@ -623,8 +605,8 @@ llvm::Value *InstructionLifter::LiftAddressOperand(
|
||||
auto index = LoadWordRegValOrZero(block, arch_addr.index_reg.name, zero);
|
||||
auto scale = llvm::ConstantInt::get(
|
||||
word_type, static_cast<uint64_t>(arch_addr.scale), true);
|
||||
auto segment = LoadWordRegValOrZero(
|
||||
block, arch_addr.segment_base_reg.name, zero);
|
||||
auto segment =
|
||||
LoadWordRegValOrZero(block, arch_addr.segment_base_reg.name, zero);
|
||||
|
||||
llvm::IRBuilder<> ir(block);
|
||||
|
||||
@@ -634,10 +616,12 @@ llvm::Value *InstructionLifter::LiftAddressOperand(
|
||||
|
||||
if (arch_addr.displacement) {
|
||||
if (0 < arch_addr.displacement) {
|
||||
addr = ir.CreateAdd(addr, llvm::ConstantInt::get(
|
||||
addr = ir.CreateAdd(
|
||||
addr, llvm::ConstantInt::get(
|
||||
word_type, static_cast<uint64_t>(arch_addr.displacement)));
|
||||
} else {
|
||||
addr = ir.CreateSub(addr, llvm::ConstantInt::get(
|
||||
addr = ir.CreateSub(
|
||||
addr, llvm::ConstantInt::get(
|
||||
word_type, static_cast<uint64_t>(-arch_addr.displacement)));
|
||||
}
|
||||
}
|
||||
@@ -653,24 +637,20 @@ llvm::Value *InstructionLifter::LiftAddressOperand(
|
||||
auto addr_type = llvm::Type::getIntNTy(
|
||||
block->getContext(), static_cast<unsigned>(arch_addr.address_size));
|
||||
|
||||
addr = ir.CreateZExt(
|
||||
ir.CreateTrunc(addr, addr_type),
|
||||
word_type);
|
||||
addr = ir.CreateZExt(ir.CreateTrunc(addr, addr_type), word_type);
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
// Lift an operand for use by the instruction.
|
||||
llvm::Value *InstructionLifter::LiftOperand(Instruction &inst,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Argument *arg,
|
||||
Operand &arch_op) {
|
||||
llvm::Value *
|
||||
InstructionLifter::LiftOperand(Instruction &inst, llvm::BasicBlock *block,
|
||||
llvm::Argument *arg, Operand &arch_op) {
|
||||
auto arg_type = arg->getType();
|
||||
switch (arch_op.type) {
|
||||
case Operand::kTypeInvalid:
|
||||
LOG(FATAL)
|
||||
<< "Decode error! Cannot lift invalid operand.";
|
||||
LOG(FATAL) << "Decode error! Cannot lift invalid operand.";
|
||||
return nullptr;
|
||||
|
||||
case Operand::kTypeShiftRegister:
|
||||
@@ -682,9 +662,9 @@ llvm::Value *InstructionLifter::LiftOperand(Instruction &inst,
|
||||
|
||||
case Operand::kTypeRegister:
|
||||
if (arch_op.size != arch_op.reg.size) {
|
||||
LOG(FATAL)
|
||||
<< "Operand size and register size must match for register "
|
||||
<< arch_op.reg.name << " in instruction " << inst.Serialize();
|
||||
LOG(FATAL) << "Operand size and register size must match for register "
|
||||
<< arch_op.reg.name << " in instruction "
|
||||
<< inst.Serialize();
|
||||
}
|
||||
return LiftRegisterOperand(inst, block, arg, arch_op);
|
||||
|
||||
@@ -693,8 +673,7 @@ llvm::Value *InstructionLifter::LiftOperand(Instruction &inst,
|
||||
|
||||
case Operand::kTypeAddress:
|
||||
if (arg_type != word_type) {
|
||||
LOG(FATAL)
|
||||
<< "Expected that a memory operand should be represented by "
|
||||
LOG(FATAL) << "Expected that a memory operand should be represented by "
|
||||
<< "machine word type. Argument type is "
|
||||
<< LLVMThingToString(arg_type) << " and word type is "
|
||||
<< LLVMThingToString(word_type) << " in instruction at "
|
||||
@@ -704,9 +683,9 @@ llvm::Value *InstructionLifter::LiftOperand(Instruction &inst,
|
||||
return LiftAddressOperand(inst, block, arg, arch_op);
|
||||
}
|
||||
|
||||
LOG(FATAL)
|
||||
<< "Got a unknown operand type of " << static_cast<int>(arch_op.type)
|
||||
<< " in instruction at " << std::hex << inst.pc;
|
||||
LOG(FATAL) << "Got a unknown operand type of "
|
||||
<< static_cast<int>(arch_op.type) << " in instruction at "
|
||||
<< std::hex << inst.pc;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -730,6 +709,7 @@ llvm::Function *TraceManager::GetLiftedTraceDefinition(uint64_t) {
|
||||
void TraceManager::ForEachDevirtualizedTarget(
|
||||
const Instruction &,
|
||||
std::function<void(uint64_t, DevirtualizedTargetKind)>) {
|
||||
|
||||
// Must be extended.
|
||||
}
|
||||
|
||||
@@ -752,8 +732,7 @@ class TraceLifter::Impl {
|
||||
|
||||
// Lift one or more traces starting from `addr`. Calls `callback` with each
|
||||
// lifted trace.
|
||||
bool Lift(
|
||||
uint64_t addr,
|
||||
bool Lift(uint64_t addr,
|
||||
std::function<void(uint64_t, llvm::Function *)> callback);
|
||||
|
||||
// Reads the bytes of an instruction at `addr` into `state.inst_bytes`.
|
||||
@@ -830,8 +809,7 @@ class TraceLifter::Impl {
|
||||
std::map<uint64_t, llvm::BasicBlock *> blocks;
|
||||
};
|
||||
|
||||
TraceLifter::Impl::Impl(InstructionLifter *inst_lifter_,
|
||||
TraceManager *manager_)
|
||||
TraceLifter::Impl::Impl(InstructionLifter *inst_lifter_, TraceManager *manager_)
|
||||
: arch(inst_lifter_->arch),
|
||||
inst_lifter(*inst_lifter_),
|
||||
intrinsics(inst_lifter.intrinsics),
|
||||
@@ -877,8 +855,7 @@ llvm::Function *TraceLifter::Impl::GetLiftedTraceDefinition(uint64_t addr) {
|
||||
auto extern_func = module->getFunction(func->getName());
|
||||
if (!extern_func || extern_func->getFunctionType() != func_type) {
|
||||
extern_func = llvm::Function::Create(
|
||||
func_type, llvm::GlobalValue::ExternalLinkage, func->getName(),
|
||||
module);
|
||||
func_type, llvm::GlobalValue::ExternalLinkage, func->getName(), module);
|
||||
|
||||
} else if (extern_func->isDeclaration()) {
|
||||
extern_func->setLinkage(llvm::GlobalValue::ExternalLinkage);
|
||||
@@ -905,9 +882,8 @@ bool TraceLifter::Impl::ReadInstructionBytes(uint64_t addr) {
|
||||
}
|
||||
uint8_t byte = 0;
|
||||
if (!manager.TryReadExecutableByte(byte_addr, &byte)) {
|
||||
DLOG(WARNING)
|
||||
<< "Couldn't read executable byte at "
|
||||
<< std::hex << byte_addr << std::dec;
|
||||
DLOG(WARNING) << "Couldn't read executable byte at " << std::hex
|
||||
<< byte_addr << std::dec;
|
||||
break;
|
||||
}
|
||||
inst_bytes.push_back(static_cast<char>(byte));
|
||||
@@ -916,18 +892,18 @@ bool TraceLifter::Impl::ReadInstructionBytes(uint64_t addr) {
|
||||
}
|
||||
|
||||
// Lift one or more traces starting from `addr`.
|
||||
bool TraceLifter::Lift(uint64_t addr,
|
||||
std::function<void(uint64_t,llvm::Function *)> callback) {
|
||||
bool TraceLifter::Lift(
|
||||
uint64_t addr, std::function<void(uint64_t, llvm::Function *)> callback) {
|
||||
return impl->Lift(addr, callback);
|
||||
}
|
||||
|
||||
// Lift one or more traces starting from `addr`.
|
||||
bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
std::function<void(uint64_t,llvm::Function *)> callback) {
|
||||
bool TraceLifter::Impl::Lift(
|
||||
uint64_t addr_, std::function<void(uint64_t, llvm::Function *)> callback) {
|
||||
auto addr = addr_ & addr_mask;
|
||||
if (addr < addr_) { // Address is out of range.
|
||||
LOG(ERROR)
|
||||
<< "Trace address " << std::hex << addr_ << " is too big" << std::dec;
|
||||
LOG(ERROR) << "Trace address " << std::hex << addr_ << " is too big"
|
||||
<< std::dec;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -967,8 +943,8 @@ bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
continue;
|
||||
}
|
||||
|
||||
DLOG(INFO)
|
||||
<< "Lifting trace at address " << std::hex << trace_addr << std::dec;
|
||||
DLOG(INFO) << "Lifting trace at address " << std::hex << trace_addr
|
||||
<< std::dec;
|
||||
|
||||
func = get_trace_decl(trace_addr);
|
||||
blocks.clear();
|
||||
@@ -992,8 +968,7 @@ bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
(void) new llvm::StoreInst(pc, next_pc_ref, entry_block);
|
||||
|
||||
// Branch to the first basic block.
|
||||
llvm::BranchInst::Create(GetOrCreateBlock(trace_addr),
|
||||
entry_block);
|
||||
llvm::BranchInst::Create(GetOrCreateBlock(trace_addr), entry_block);
|
||||
}
|
||||
|
||||
CHECK(inst_work_list.empty());
|
||||
@@ -1044,7 +1019,8 @@ bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
if (!ReadInstructionBytes(inst.delayed_pc) ||
|
||||
!arch->DecodeDelayedInstruction(inst.delayed_pc, inst_bytes,
|
||||
delayed_inst)) {
|
||||
LOG(ERROR) << "Couldn't read delayed inst " << delayed_inst.Serialize();
|
||||
LOG(ERROR) << "Couldn't read delayed inst "
|
||||
<< delayed_inst.Serialize();
|
||||
AddTerminatingTailCall(block, intrinsics->error);
|
||||
continue;
|
||||
}
|
||||
@@ -1060,8 +1036,8 @@ bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
on_branch_taken_path)) {
|
||||
return;
|
||||
}
|
||||
lift_status = inst_lifter.LiftIntoBlock(
|
||||
delayed_inst, into_block, true /* is_delayed */);
|
||||
lift_status = inst_lifter.LiftIntoBlock(delayed_inst, into_block,
|
||||
true /* is_delayed */);
|
||||
if (kLiftedInstruction != lift_status) {
|
||||
AddTerminatingTailCall(block, intrinsics->error);
|
||||
}
|
||||
@@ -1100,8 +1076,8 @@ bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
inst,
|
||||
[&](uint64_t target_addr, DevirtualizedTargetKind target_kind) {
|
||||
if (target_kind == DevirtualizedTargetKind::kTraceHead) {
|
||||
auto target_block = llvm::BasicBlock::Create(
|
||||
context, "", func);
|
||||
auto target_block =
|
||||
llvm::BasicBlock::Create(context, "", func);
|
||||
devirt_targets[target_addr] = target_block;
|
||||
|
||||
// Always add to the work list. This will cause us to lift
|
||||
@@ -1130,8 +1106,7 @@ bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
pc, default_case, devirt_targets.size(), block);
|
||||
for (auto devirt_target : devirt_targets) {
|
||||
dispatcher->addCase(
|
||||
llvm::dyn_cast<llvm::ConstantInt>(
|
||||
llvm::ConstantInt::get(
|
||||
llvm::dyn_cast<llvm::ConstantInt>(llvm::ConstantInt::get(
|
||||
pc_type, devirt_target.first, false)),
|
||||
devirt_target.second);
|
||||
}
|
||||
@@ -1144,11 +1119,13 @@ bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
|
||||
case Instruction::kCategoryIndirectFunctionCall: {
|
||||
try_add_delay_slot(true, block);
|
||||
const auto fall_through_block = llvm::BasicBlock::Create(
|
||||
context, "", func);
|
||||
const auto fall_through_block =
|
||||
llvm::BasicBlock::Create(context, "", func);
|
||||
|
||||
const auto ret_pc_ref = LoadReturnProgramCounterRef(fall_through_block);
|
||||
const auto next_pc_ref = LoadNextProgramCounterRef(fall_through_block);
|
||||
const auto ret_pc_ref =
|
||||
LoadReturnProgramCounterRef(fall_through_block);
|
||||
const auto next_pc_ref =
|
||||
LoadNextProgramCounterRef(fall_through_block);
|
||||
llvm::IRBuilder<> ir(fall_through_block);
|
||||
ir.CreateStore(ir.CreateLoad(ret_pc_ref), next_pc_ref);
|
||||
ir.CreateBr(GetOrCreateNextBlock());
|
||||
@@ -1165,8 +1142,7 @@ bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
return;
|
||||
}
|
||||
|
||||
auto target_block = llvm::BasicBlock::Create(
|
||||
context, "", func);
|
||||
auto target_block = llvm::BasicBlock::Create(context, "", func);
|
||||
devirt_targets[target_addr] = target_block;
|
||||
|
||||
// Always add to the work list. This will cause us to lift
|
||||
@@ -1195,8 +1171,7 @@ bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
pc, default_case, devirt_targets.size(), block);
|
||||
for (auto devirt_target : devirt_targets) {
|
||||
dispatcher->addCase(
|
||||
llvm::dyn_cast<llvm::ConstantInt>(
|
||||
llvm::ConstantInt::get(
|
||||
llvm::dyn_cast<llvm::ConstantInt>(llvm::ConstantInt::get(
|
||||
pc_type, devirt_target.first, false)),
|
||||
devirt_target.second);
|
||||
}
|
||||
@@ -1238,11 +1213,8 @@ bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
// checking if the hyper call returns to the next PC or not.
|
||||
case Instruction::kCategoryConditionalAsyncHyperCall: {
|
||||
auto do_hyper_call = llvm::BasicBlock::Create(context, "", func);
|
||||
llvm::BranchInst::Create(
|
||||
do_hyper_call,
|
||||
GetOrCreateNextBlock(),
|
||||
LoadBranchTaken(block),
|
||||
block);
|
||||
llvm::BranchInst::Create(do_hyper_call, GetOrCreateNextBlock(),
|
||||
LoadBranchTaken(block), block);
|
||||
block = do_hyper_call;
|
||||
AddCall(block, intrinsics->async_hyper_call);
|
||||
goto check_call_return;
|
||||
@@ -1251,15 +1223,16 @@ bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
check_call_return:
|
||||
do {
|
||||
auto pc = LoadProgramCounter(block);
|
||||
auto ret_pc = llvm::ConstantInt::get(
|
||||
inst_lifter.word_type, inst.next_pc);
|
||||
auto ret_pc =
|
||||
llvm::ConstantInt::get(inst_lifter.word_type, inst.next_pc);
|
||||
|
||||
llvm::IRBuilder<> ir(block);
|
||||
auto eq = ir.CreateICmpEQ(pc, ret_pc);
|
||||
auto unexpected_ret_pc = llvm::BasicBlock::Create(
|
||||
context, "", func);
|
||||
auto unexpected_ret_pc =
|
||||
llvm::BasicBlock::Create(context, "", func);
|
||||
ir.CreateCondBr(eq, GetOrCreateNextBlock(), unexpected_ret_pc);
|
||||
AddTerminatingTailCall(unexpected_ret_pc, intrinsics->missing_block);
|
||||
AddTerminatingTailCall(unexpected_ret_pc,
|
||||
intrinsics->missing_block);
|
||||
} while (false);
|
||||
break;
|
||||
|
||||
@@ -1278,8 +1251,8 @@ bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
// and its original targets.
|
||||
if (try_delay) {
|
||||
auto new_taken_block = llvm::BasicBlock::Create(context, "", func);
|
||||
auto new_not_taken_block = llvm::BasicBlock::Create(
|
||||
context, "", func);
|
||||
auto new_not_taken_block =
|
||||
llvm::BasicBlock::Create(context, "", func);
|
||||
|
||||
try_add_delay_slot(true, new_taken_block);
|
||||
try_add_delay_slot(false, new_not_taken_block);
|
||||
@@ -1291,11 +1264,8 @@ bool TraceLifter::Impl::Lift(uint64_t addr_,
|
||||
not_taken_block = new_not_taken_block;
|
||||
}
|
||||
|
||||
llvm::BranchInst::Create(
|
||||
taken_block,
|
||||
not_taken_block,
|
||||
LoadBranchTaken(block),
|
||||
block);
|
||||
llvm::BranchInst::Create(taken_block, not_taken_block,
|
||||
LoadBranchTaken(block), block);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+19
-33
@@ -20,7 +20,6 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llvm {
|
||||
@@ -60,17 +59,15 @@ class InstructionLifter {
|
||||
const IntrinsicTable &intrinsics_)
|
||||
: InstructionLifter(arch_.get(), &intrinsics_) {}
|
||||
|
||||
inline InstructionLifter(const Arch *arch_,
|
||||
const IntrinsicTable &intrinsics_)
|
||||
inline InstructionLifter(const Arch *arch_, const IntrinsicTable &intrinsics_)
|
||||
: InstructionLifter(arch_, &intrinsics_) {}
|
||||
|
||||
InstructionLifter(const Arch *arch_,
|
||||
const IntrinsicTable *intrinsics_);
|
||||
InstructionLifter(const Arch *arch_, const IntrinsicTable *intrinsics_);
|
||||
|
||||
// Lift a single instruction into a basic block. `is_delayed` signifies that
|
||||
// this instruction will execute within the delay slot of another instruction.
|
||||
virtual LiftStatus LiftIntoBlock(
|
||||
Instruction &inst, llvm::BasicBlock *block, bool is_delayed=false);
|
||||
virtual LiftStatus LiftIntoBlock(Instruction &inst, llvm::BasicBlock *block,
|
||||
bool is_delayed = false);
|
||||
|
||||
const Arch *const arch;
|
||||
|
||||
@@ -92,34 +89,28 @@ class InstructionLifter {
|
||||
friend class TraceLifter;
|
||||
|
||||
// Lift an operand to an instruction.
|
||||
virtual llvm::Value *LiftOperand(Instruction &inst,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Argument *arg,
|
||||
Operand &op);
|
||||
virtual llvm::Value *LiftOperand(Instruction &inst, llvm::BasicBlock *block,
|
||||
llvm::Argument *arg, Operand &op);
|
||||
|
||||
// Lift a register operand to a value.
|
||||
virtual llvm::Value *LiftShiftRegisterOperand(Instruction &inst,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Argument *arg,
|
||||
Operand ®);
|
||||
virtual llvm::Value *
|
||||
LiftShiftRegisterOperand(Instruction &inst, llvm::BasicBlock *block,
|
||||
llvm::Argument *arg, Operand ®);
|
||||
|
||||
// Lift a register operand to a value.
|
||||
virtual llvm::Value *LiftRegisterOperand(Instruction &inst,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Argument *arg,
|
||||
Operand ®);
|
||||
llvm::Argument *arg, Operand ®);
|
||||
|
||||
// Lift an immediate operand.
|
||||
virtual llvm::Value *LiftImmediateOperand(Instruction &inst,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Argument *arg,
|
||||
Operand &op);
|
||||
llvm::Argument *arg, Operand &op);
|
||||
|
||||
// Lift an indirect memory operand to a value.
|
||||
virtual llvm::Value *LiftAddressOperand(Instruction &inst,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Argument *arg,
|
||||
Operand &mem);
|
||||
llvm::Argument *arg, Operand &mem);
|
||||
|
||||
// Return a register value, or zero.
|
||||
llvm::Value *LoadWordRegValOrZero(llvm::BasicBlock *block,
|
||||
@@ -138,10 +129,7 @@ class InstructionLifter {
|
||||
|
||||
using TraceMap = std::unordered_map<uint64_t, llvm::Function *>;
|
||||
|
||||
enum class DevirtualizedTargetKind {
|
||||
kTraceLocal,
|
||||
kTraceHead
|
||||
};
|
||||
enum class DevirtualizedTargetKind { kTraceLocal, kTraceHead };
|
||||
|
||||
// Manages information about traces. Permits a user of the trace lifter to
|
||||
// provide more global information to the decoder as it goes, e.g. by pre-
|
||||
@@ -158,8 +146,8 @@ class TraceManager {
|
||||
|
||||
// Called when we have lifted, i.e. defined the contents, of a new trace.
|
||||
// The derived class is expected to do something useful with this.
|
||||
virtual void SetLiftedTraceDefinition(
|
||||
uint64_t addr, llvm::Function *lifted_func) = 0;
|
||||
virtual void SetLiftedTraceDefinition(uint64_t addr,
|
||||
llvm::Function *lifted_func) = 0;
|
||||
|
||||
// Get a declaration for a lifted trace. The idea here is that a derived
|
||||
// class might have additional global info available to them that lets
|
||||
@@ -202,19 +190,17 @@ class TraceLifter {
|
||||
public:
|
||||
~TraceLifter(void);
|
||||
|
||||
inline TraceLifter(InstructionLifter &inst_lifter_,
|
||||
TraceManager &manager_)
|
||||
inline TraceLifter(InstructionLifter &inst_lifter_, TraceManager &manager_)
|
||||
: TraceLifter(&inst_lifter_, &manager_) {}
|
||||
|
||||
TraceLifter(InstructionLifter *inst_lifter_,
|
||||
TraceManager *manager_);
|
||||
TraceLifter(InstructionLifter *inst_lifter_, TraceManager *manager_);
|
||||
|
||||
static void NullCallback(uint64_t, llvm::Function *);
|
||||
|
||||
// Lift one or more traces starting from `addr`. Calls `callback` with each
|
||||
// lifted trace.
|
||||
bool Lift(
|
||||
uint64_t addr,
|
||||
bool
|
||||
Lift(uint64_t addr,
|
||||
std::function<void(uint64_t, llvm::Function *)> callback = NullCallback);
|
||||
|
||||
private:
|
||||
|
||||
+12
-18
@@ -14,42 +14,37 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "remill/BC/Optimizer.h"
|
||||
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <llvm/ADT/Triple.h>
|
||||
|
||||
#include <llvm/IR/Constants.h>
|
||||
#include <llvm/IR/DataLayout.h>
|
||||
#include <llvm/IR/DebugInfo.h>
|
||||
#include <llvm/IR/InstIterator.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/LegacyPassManager.h>
|
||||
#include <llvm/IR/InstIterator.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Metadata.h>
|
||||
#include <llvm/IR/LegacyPassManager.h>
|
||||
#include <llvm/IR/MDBuilder.h>
|
||||
#include <llvm/IR/Metadata.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
|
||||
#include <llvm/Transforms/IPO.h>
|
||||
#include <llvm/Transforms/IPO/PassManagerBuilder.h>
|
||||
#include <llvm/Transforms/Scalar.h>
|
||||
#include <llvm/Transforms/Utils/Local.h>
|
||||
#include <llvm/Transforms/Utils/Cloning.h>
|
||||
#include <llvm/Transforms/Utils/Local.h>
|
||||
#include <llvm/Transforms/Utils/ValueMapper.h>
|
||||
|
||||
#include "remill/Arch/Arch.h"
|
||||
|
||||
#include "remill/BC/Compat/ScalarTransforms.h"
|
||||
#include "remill/BC/Compat/TargetLibraryInfo.h"
|
||||
|
||||
#include "remill/BC/DeadStoreEliminator.h"
|
||||
#include "remill/BC/Optimizer.h"
|
||||
#include "remill/BC/Util.h"
|
||||
|
||||
namespace remill {
|
||||
|
||||
void OptimizeModule(const remill::Arch *arch,
|
||||
llvm::Module *module,
|
||||
void OptimizeModule(const remill::Arch *arch, llvm::Module *module,
|
||||
std::function<llvm::Function *(void)> generator,
|
||||
OptimizationGuide guide) {
|
||||
|
||||
@@ -59,8 +54,8 @@ void OptimizeModule(const remill::Arch *arch,
|
||||
llvm::legacy::FunctionPassManager func_manager(module);
|
||||
llvm::legacy::PassManager module_manager;
|
||||
|
||||
auto TLI = new llvm::TargetLibraryInfoImpl(
|
||||
llvm::Triple(module->getTargetTriple()));
|
||||
auto TLI =
|
||||
new llvm::TargetLibraryInfoImpl(llvm::Triple(module->getTargetTriple()));
|
||||
|
||||
TLI->disableAllFunctions(); // `-fno-builtin`.
|
||||
|
||||
@@ -100,14 +95,13 @@ void OptimizeModule(const remill::Arch *arch,
|
||||
//
|
||||
// NOTE(pag): It is an error to specify `guide.eliminate_dead_stores` as
|
||||
// `true`.
|
||||
void OptimizeBareModule(
|
||||
llvm::Module *module, OptimizationGuide guide) {
|
||||
void OptimizeBareModule(llvm::Module *module, OptimizationGuide guide) {
|
||||
CHECK(!guide.eliminate_dead_stores);
|
||||
llvm::legacy::FunctionPassManager func_manager(module);
|
||||
llvm::legacy::PassManager module_manager;
|
||||
|
||||
auto TLI = new llvm::TargetLibraryInfoImpl(
|
||||
llvm::Triple(module->getTargetTriple()));
|
||||
auto TLI =
|
||||
new llvm::TargetLibraryInfoImpl(llvm::Triple(module->getTargetTriple()));
|
||||
|
||||
TLI->disableAllFunctions(); // `-fno-builtin`.
|
||||
|
||||
|
||||
+26
-39
@@ -19,14 +19,16 @@
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include <llvm/IR/Module.h>
|
||||
|
||||
namespace llvm {
|
||||
class Function;
|
||||
class Module;
|
||||
} // namespace llvm
|
||||
namespace remill {
|
||||
|
||||
@@ -41,28 +43,23 @@ struct OptimizationGuide {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline static void OptimizeModule(
|
||||
const std::unique_ptr<const remill::Arch> &arch,
|
||||
const std::unique_ptr<llvm::Module> &module,
|
||||
T &&generator,
|
||||
inline static void
|
||||
OptimizeModule(const std::unique_ptr<const remill::Arch> &arch,
|
||||
const std::unique_ptr<llvm::Module> &module, T &&generator,
|
||||
OptimizationGuide guide = {}) {
|
||||
return OptimizeModule(arch.get(), module.get(), generator, guide);
|
||||
}
|
||||
|
||||
void OptimizeModule(
|
||||
const remill::Arch *arch,
|
||||
llvm::Module *module,
|
||||
void OptimizeModule(const remill::Arch *arch, llvm::Module *module,
|
||||
std::function<llvm::Function *(void)> generator,
|
||||
OptimizationGuide guide = {});
|
||||
|
||||
inline static void OptimizeModule(
|
||||
const remill::Arch *arch,
|
||||
llvm::Module *module,
|
||||
inline static void
|
||||
OptimizeModule(const remill::Arch *arch, llvm::Module *module,
|
||||
std::initializer_list<llvm::Function *> traces,
|
||||
OptimizationGuide guide = {}) {
|
||||
auto trace_it = traces.begin();
|
||||
auto trace_func_gen =
|
||||
[&trace_it, &traces] (void) -> llvm::Function * {
|
||||
auto trace_func_gen = [&trace_it, &traces](void) -> llvm::Function * {
|
||||
if (trace_it != traces.end()) {
|
||||
auto lifted_func = *trace_it;
|
||||
trace_it++;
|
||||
@@ -75,14 +72,12 @@ inline static void OptimizeModule(
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
inline static void OptimizeModule(
|
||||
const remill::Arch *arch,
|
||||
llvm::Module *module,
|
||||
inline static void
|
||||
OptimizeModule(const remill::Arch *arch, llvm::Module *module,
|
||||
const std::unordered_map<K, llvm::Function *> &traces,
|
||||
OptimizationGuide guide = {}) {
|
||||
auto trace_it = traces.begin();
|
||||
auto trace_func_gen =
|
||||
[&trace_it, &traces] (void) -> llvm::Function * {
|
||||
auto trace_func_gen = [&trace_it, &traces](void) -> llvm::Function * {
|
||||
if (trace_it != traces.end()) {
|
||||
auto lifted_func = trace_it->second;
|
||||
trace_it++;
|
||||
@@ -95,14 +90,12 @@ inline static void OptimizeModule(
|
||||
}
|
||||
|
||||
template <typename K>
|
||||
inline static void OptimizeModule(
|
||||
const remill::Arch *arch,
|
||||
inline static void OptimizeModule(const remill::Arch *arch,
|
||||
llvm::Module *module,
|
||||
const std::map<K, llvm::Function *> &traces,
|
||||
OptimizationGuide guide = {}) {
|
||||
auto trace_it = traces.begin();
|
||||
auto trace_func_gen =
|
||||
[&trace_it, &traces] (void) -> llvm::Function * {
|
||||
auto trace_func_gen = [&trace_it, &traces](void) -> llvm::Function * {
|
||||
if (trace_it != traces.end()) {
|
||||
auto lifted_func = trace_it->second;
|
||||
trace_it++;
|
||||
@@ -114,14 +107,12 @@ inline static void OptimizeModule(
|
||||
return OptimizeModule(arch, module, trace_func_gen, guide);
|
||||
}
|
||||
|
||||
inline static void OptimizeModule(
|
||||
const remill::Arch *arch,
|
||||
inline static void OptimizeModule(const remill::Arch *arch,
|
||||
llvm::Module *module,
|
||||
const std::set<llvm::Function *> &traces,
|
||||
OptimizationGuide guide = {}) {
|
||||
auto trace_it = traces.begin();
|
||||
auto trace_func_gen =
|
||||
[&trace_it, &traces] (void) -> llvm::Function * {
|
||||
auto trace_func_gen = [&trace_it, &traces](void) -> llvm::Function * {
|
||||
if (trace_it != traces.end()) {
|
||||
auto lifted_func = *trace_it;
|
||||
trace_it++;
|
||||
@@ -133,14 +124,12 @@ inline static void OptimizeModule(
|
||||
return OptimizeModule(arch, module, trace_func_gen, guide);
|
||||
}
|
||||
|
||||
inline static void OptimizeModule(
|
||||
const remill::Arch *arch,
|
||||
llvm::Module *module,
|
||||
inline static void
|
||||
OptimizeModule(const remill::Arch *arch, llvm::Module *module,
|
||||
const std::unordered_set<llvm::Function *> &traces,
|
||||
OptimizationGuide guide = {}) {
|
||||
auto trace_it = traces.begin();
|
||||
auto trace_func_gen =
|
||||
[&trace_it, &traces] (void) -> llvm::Function * {
|
||||
auto trace_func_gen = [&trace_it, &traces](void) -> llvm::Function * {
|
||||
if (trace_it != traces.end()) {
|
||||
auto lifted_func = *trace_it;
|
||||
trace_it++;
|
||||
@@ -152,14 +141,12 @@ inline static void OptimizeModule(
|
||||
return OptimizeModule(arch, module, trace_func_gen, guide);
|
||||
}
|
||||
|
||||
inline static void OptimizeModule(
|
||||
const remill::Arch *arch,
|
||||
inline static void OptimizeModule(const remill::Arch *arch,
|
||||
llvm::Module *module,
|
||||
const std::vector<llvm::Function *> &traces,
|
||||
OptimizationGuide guide = {}) {
|
||||
auto trace_it = traces.begin();
|
||||
auto trace_func_gen =
|
||||
[&trace_it, &traces] (void) -> llvm::Function * {
|
||||
auto trace_func_gen = [&trace_it, &traces](void) -> llvm::Function * {
|
||||
if (trace_it != traces.end()) {
|
||||
auto lifted_func = *trace_it;
|
||||
trace_it++;
|
||||
@@ -178,8 +165,8 @@ inline static void OptimizeModule(
|
||||
// `true`.
|
||||
void OptimizeBareModule(llvm::Module *module, OptimizationGuide guide = {});
|
||||
|
||||
inline static void OptimizeBareModule(
|
||||
const std::unique_ptr<llvm::Module> &module,
|
||||
inline static void
|
||||
OptimizeBareModule(const std::unique_ptr<llvm::Module> &module,
|
||||
OptimizationGuide guide = {}) {
|
||||
std::vector<llvm::Function *> funcs;
|
||||
for (auto &func : *module) {
|
||||
|
||||
+156
-212
@@ -30,7 +30,6 @@
|
||||
|
||||
#include <llvm/ADT/SmallVector.h>
|
||||
#include <llvm/ADT/StringExtras.h>
|
||||
|
||||
#include <llvm/IR/BasicBlock.h>
|
||||
#include <llvm/IR/Constants.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
@@ -40,7 +39,6 @@
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Metadata.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
|
||||
#include <llvm/Support/FileSystem.h>
|
||||
#include <llvm/Support/SourceMgr.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
@@ -76,11 +74,13 @@ std::uint32_t nativeGetProcessID(void) {
|
||||
return getpid();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace remill {
|
||||
|
||||
// Initialize the attributes for a lifted function.
|
||||
void InitFunctionAttributes(llvm::Function *function) {
|
||||
|
||||
// Make sure functions are treated as if they return. LLVM doesn't like
|
||||
// mixing must-tail-calls with no-return.
|
||||
function->removeFnAttr(llvm::Attribute::NoReturn);
|
||||
@@ -133,8 +133,7 @@ llvm::CallInst *AddTerminatingTailCall(llvm::BasicBlock *source_block,
|
||||
|
||||
// Find a local variable defined in the entry block of the function. We use
|
||||
// this to find register variables.
|
||||
llvm::Value *FindVarInFunction(llvm::BasicBlock *block,
|
||||
const std::string &name,
|
||||
llvm::Value *FindVarInFunction(llvm::BasicBlock *block, const std::string &name,
|
||||
bool allow_failure) {
|
||||
return FindVarInFunction(block->getParent(), name, allow_failure);
|
||||
}
|
||||
@@ -142,8 +141,7 @@ llvm::Value *FindVarInFunction(llvm::BasicBlock *block,
|
||||
// Find a local variable defined in the entry block of the function. We use
|
||||
// this to find register variables.
|
||||
llvm::Value *FindVarInFunction(llvm::Function *function,
|
||||
const std::string &name,
|
||||
bool allow_failure) {
|
||||
const std::string &name, bool allow_failure) {
|
||||
if (!function->empty()) {
|
||||
for (auto &instr : function->getEntryBlock()) {
|
||||
if (instr.getName() == name) {
|
||||
@@ -266,8 +264,8 @@ llvm::Value *LoadMemoryPointer(llvm::BasicBlock *block) {
|
||||
// or not a conditional branch is taken.
|
||||
llvm::Value *LoadBranchTaken(llvm::BasicBlock *block) {
|
||||
llvm::IRBuilder<> ir(block);
|
||||
auto cond = ir.CreateLoad(
|
||||
FindVarInFunction(block->getParent(), "BRANCH_TAKEN"));
|
||||
auto cond =
|
||||
ir.CreateLoad(FindVarInFunction(block->getParent(), "BRANCH_TAKEN"));
|
||||
auto true_val = llvm::ConstantInt::get(cond->getType(), 1);
|
||||
return ir.CreateICmpEQ(cond, true_val);
|
||||
}
|
||||
@@ -298,8 +296,7 @@ llvm::GlobalVariable *FindGlobaVariable(llvm::Module *module,
|
||||
std::unique_ptr<llvm::Module> LoadArchSemantics(const Arch *arch) {
|
||||
auto arch_name = GetArchName(arch->arch_name);
|
||||
auto path = FindSemanticsBitcodeFile(arch_name);
|
||||
LOG(INFO)
|
||||
<< "Loading " << arch_name << " semantics from file " << path;
|
||||
LOG(INFO) << "Loading " << arch_name << " semantics from file " << path;
|
||||
auto module = LoadModuleFromFile(arch->context, path);
|
||||
arch->PrepareModule(module);
|
||||
for (auto &func : *module) {
|
||||
@@ -326,8 +323,7 @@ bool VerifyModule(llvm::Module *module) {
|
||||
llvm::raw_string_ostream error_stream(error);
|
||||
if (llvm::verifyModule(*module, &error_stream)) {
|
||||
error_stream.flush();
|
||||
LOG(ERROR)
|
||||
<< "Error verifying module read from file: " << error;
|
||||
LOG(ERROR) << "Error verifying module read from file: " << error;
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@@ -342,8 +338,7 @@ std::unique_ptr<llvm::Module> LoadModuleFromFile(llvm::LLVMContext *context,
|
||||
auto module = llvm::parseIRFile(file_name, err, *context);
|
||||
|
||||
if (!module) {
|
||||
LOG_IF(FATAL, !allow_failure)
|
||||
<< "Unable to parse module file " << file_name
|
||||
LOG_IF(FATAL, !allow_failure) << "Unable to parse module file " << file_name
|
||||
<< ": " << err.getMessage().str();
|
||||
return {};
|
||||
}
|
||||
@@ -367,8 +362,7 @@ std::unique_ptr<llvm::Module> LoadModuleFromFile(llvm::LLVMContext *context,
|
||||
// Store an LLVM module into a file.
|
||||
bool StoreModuleToFile(llvm::Module *module, const std::string &file_name,
|
||||
bool allow_failure) {
|
||||
DLOG(INFO)
|
||||
<< "Saving bitcode to file " << file_name;
|
||||
DLOG(INFO) << "Saving bitcode to file " << file_name;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << file_name << ".tmp." << nativeGetProcessID();
|
||||
@@ -433,8 +427,7 @@ bool StoreModuleIRToFile(llvm::Module *module, const std::string &file_name,
|
||||
#endif
|
||||
if (!good) {
|
||||
LOG_IF(FATAL, allow_failure)
|
||||
<< "Could not save LLVM IR to " << file_name
|
||||
<< ": " << error;
|
||||
<< "Could not save LLVM IR to " << file_name << ": " << error;
|
||||
return false;
|
||||
}
|
||||
module->print(dest, nullptr);
|
||||
@@ -444,12 +437,14 @@ bool StoreModuleIRToFile(llvm::Module *module, const std::string &file_name,
|
||||
namespace {
|
||||
|
||||
#ifndef REMILL_BUILD_SEMANTICS_DIR_X86
|
||||
#error "Macro `REMILL_BUILD_SEMANTICS_DIR_X86` must be defined to support X86 and AMD64 architectures."
|
||||
# error \
|
||||
"Macro `REMILL_BUILD_SEMANTICS_DIR_X86` must be defined to support X86 and AMD64 architectures."
|
||||
# define REMILL_BUILD_SEMANTICS_DIR_X86
|
||||
#endif // REMILL_BUILD_SEMANTICS_DIR_X86
|
||||
|
||||
#ifndef REMILL_BUILD_SEMANTICS_DIR_AARCH64
|
||||
#error "Macro `REMILL_BUILD_SEMANTICS_DIR_AARCH64` must be defined to support AArch64 architecture."
|
||||
# error \
|
||||
"Macro `REMILL_BUILD_SEMANTICS_DIR_AARCH64` must be defined to support AArch64 architecture."
|
||||
# define REMILL_BUILD_SEMANTICS_DIR_AARCH64
|
||||
#endif // REMILL_BUILD_SEMANTICS_DIR_AARCH64
|
||||
|
||||
@@ -463,6 +458,7 @@ namespace {
|
||||
#define MAJOR_MINOR S(LLVM_VERSION_MAJOR) "." S(LLVM_VERSION_MINOR)
|
||||
|
||||
static const char *gSemanticsSearchPaths[] = {
|
||||
|
||||
// Derived from the build.
|
||||
REMILL_BUILD_SEMANTICS_DIR_X86 "\0",
|
||||
REMILL_BUILD_SEMANTICS_DIR_AARCH64 "\0",
|
||||
@@ -496,8 +492,7 @@ std::string FindSemanticsBitcodeFile(const std::string &arch) {
|
||||
}
|
||||
}
|
||||
|
||||
LOG(FATAL)
|
||||
<< "Cannot find path to " << arch << " semantics bitcode file.";
|
||||
LOG(FATAL) << "Cannot find path to " << arch << " semantics bitcode file.";
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -550,8 +545,8 @@ llvm::FunctionType *LiftedFunctionType(llvm::Module *module) {
|
||||
|
||||
// Return a vector of arguments to pass to a lifted function, where the
|
||||
// arguments are derived from `block`.
|
||||
std::array<llvm::Value *, kNumBlockArgs> LiftedFunctionArgs(
|
||||
llvm::BasicBlock *block) {
|
||||
std::array<llvm::Value *, kNumBlockArgs>
|
||||
LiftedFunctionArgs(llvm::BasicBlock *block) {
|
||||
auto func = block->getParent();
|
||||
|
||||
// Set up arguments according to our ABI.
|
||||
@@ -592,8 +587,8 @@ llvm::Function *DeclareLiftedFunction(llvm::Module *module,
|
||||
if (!func) {
|
||||
auto bb = BasicBlockFunction(module);
|
||||
auto func_type = bb->getFunctionType();
|
||||
func = llvm::Function::Create(
|
||||
func_type, llvm::GlobalValue::InternalLinkage, name, module);
|
||||
func = llvm::Function::Create(func_type, llvm::GlobalValue::InternalLinkage,
|
||||
name, module);
|
||||
InitFunctionAttributes(func);
|
||||
}
|
||||
|
||||
@@ -733,8 +728,8 @@ static llvm::Function *DeclareFunctionInModule(llvm::Function *func,
|
||||
<< "Cannot declare internal function " << func->getName().str()
|
||||
<< " as external in another module";
|
||||
|
||||
dest_func = llvm::Function::Create(
|
||||
func->getFunctionType(), func->getLinkage(),
|
||||
dest_func =
|
||||
llvm::Function::Create(func->getFunctionType(), func->getLinkage(),
|
||||
func->getName(), dest_module);
|
||||
|
||||
dest_func->copyAttributesFrom(func);
|
||||
@@ -755,8 +750,8 @@ static void ClearMetaData(T *value) {
|
||||
}
|
||||
}
|
||||
|
||||
static llvm::Constant *MoveConstantIntoModule(
|
||||
llvm::Constant *c, llvm::Module *dest_module) {
|
||||
static llvm::Constant *MoveConstantIntoModule(llvm::Constant *c,
|
||||
llvm::Module *dest_module) {
|
||||
|
||||
auto &dest_context = dest_module->getContext();
|
||||
auto type = c->getType();
|
||||
@@ -853,8 +848,7 @@ static llvm::Constant *MoveConstantIntoModule(
|
||||
return llvm::ConstantDataArray::get(dest_context, ref);
|
||||
}
|
||||
|
||||
LOG(FATAL)
|
||||
<< "Unsupported element type in constant data array: "
|
||||
LOG(FATAL) << "Unsupported element type in constant data array: "
|
||||
<< remill::LLVMThingToString(el_type);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -868,14 +862,12 @@ static llvm::Constant *MoveConstantIntoModule(
|
||||
}
|
||||
|
||||
} else if (in_same_context) {
|
||||
LOG(ERROR)
|
||||
<< "Not adapting constant when moving to destination module: "
|
||||
LOG(ERROR) << "Not adapting constant when moving to destination module: "
|
||||
<< LLVMThingToString(c);
|
||||
return c;
|
||||
|
||||
} else {
|
||||
LOG(FATAL)
|
||||
<< "Cannot move constant to destination context: "
|
||||
LOG(FATAL) << "Cannot move constant to destination context: "
|
||||
<< LLVMThingToString(c);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -914,16 +906,13 @@ static llvm::Constant *MoveConstantIntoModule(
|
||||
MoveConstantIntoModule(ce->getOperand(1), dest_module));
|
||||
case llvm::Instruction::ZExt:
|
||||
return llvm::ConstantExpr::getZExt(
|
||||
MoveConstantIntoModule(ce->getOperand(0), dest_module),
|
||||
type);
|
||||
MoveConstantIntoModule(ce->getOperand(0), dest_module), type);
|
||||
case llvm::Instruction::SExt:
|
||||
return llvm::ConstantExpr::getSExt(
|
||||
MoveConstantIntoModule(ce->getOperand(0), dest_module),
|
||||
type);
|
||||
MoveConstantIntoModule(ce->getOperand(0), dest_module), type);
|
||||
case llvm::Instruction::Trunc:
|
||||
return llvm::ConstantExpr::getTrunc(
|
||||
MoveConstantIntoModule(ce->getOperand(0), dest_module),
|
||||
type);
|
||||
MoveConstantIntoModule(ce->getOperand(0), dest_module), type);
|
||||
case llvm::Instruction::Select:
|
||||
return llvm::ConstantExpr::getSelect(
|
||||
MoveConstantIntoModule(ce->getOperand(0), dest_module),
|
||||
@@ -974,16 +963,13 @@ static llvm::Constant *MoveConstantIntoModule(
|
||||
MoveConstantIntoModule(ce->getOperand(1), dest_module));
|
||||
case llvm::Instruction::IntToPtr:
|
||||
return llvm::ConstantExpr::getIntToPtr(
|
||||
MoveConstantIntoModule(ce->getOperand(0), dest_module),
|
||||
type);
|
||||
MoveConstantIntoModule(ce->getOperand(0), dest_module), type);
|
||||
case llvm::Instruction::PtrToInt:
|
||||
return llvm::ConstantExpr::getPtrToInt(
|
||||
MoveConstantIntoModule(ce->getOperand(0), dest_module),
|
||||
type);
|
||||
MoveConstantIntoModule(ce->getOperand(0), dest_module), type);
|
||||
case llvm::Instruction::BitCast:
|
||||
return llvm::ConstantExpr::getBitCast(
|
||||
MoveConstantIntoModule(ce->getOperand(0), dest_module),
|
||||
type);
|
||||
MoveConstantIntoModule(ce->getOperand(0), dest_module), type);
|
||||
case llvm::Instruction::GetElementPtr: {
|
||||
const auto g = llvm::dyn_cast<llvm::GEPOperator>(ce);
|
||||
const auto ni = g->getNumIndices();
|
||||
@@ -991,7 +977,8 @@ static llvm::Constant *MoveConstantIntoModule(
|
||||
g->getSourceElementType(), dest_context);
|
||||
std::vector<llvm::Constant *> indices(ni);
|
||||
for (auto i = 0u; i < ni; ++i) {
|
||||
indices[i] = MoveConstantIntoModule(ce->getOperand(i + 1u), dest_module);
|
||||
indices[i] =
|
||||
MoveConstantIntoModule(ce->getOperand(i + 1u), dest_module);
|
||||
}
|
||||
return llvm::ConstantExpr::getGetElementPtr(
|
||||
source_type, MoveConstantIntoModule(ce->getOperand(0), dest_module),
|
||||
@@ -999,14 +986,12 @@ static llvm::Constant *MoveConstantIntoModule(
|
||||
}
|
||||
default:
|
||||
if (in_same_context) {
|
||||
LOG(ERROR)
|
||||
<< "Unsupported CE when moving across module boundaries: "
|
||||
LOG(ERROR) << "Unsupported CE when moving across module boundaries: "
|
||||
<< LLVMThingToString(ce);
|
||||
return ce;
|
||||
|
||||
} else {
|
||||
LOG(FATAL)
|
||||
<< "Unsupported CE when moving across context boundaries: "
|
||||
LOG(FATAL) << "Unsupported CE when moving across context boundaries: "
|
||||
<< LLVMThingToString(ce);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1020,8 +1005,8 @@ static llvm::Constant *MoveConstantIntoModule(
|
||||
llvm::cast<llvm::Constant>(it->get()), dest_module));
|
||||
}
|
||||
|
||||
return llvm::ConstantArray::get(
|
||||
llvm::cast<llvm::ArrayType>(type), new_elems);
|
||||
return llvm::ConstantArray::get(llvm::cast<llvm::ArrayType>(type),
|
||||
new_elems);
|
||||
|
||||
} else if (auto s = llvm::dyn_cast<llvm::ConstantStruct>(ca); s) {
|
||||
std::vector<llvm::Constant *> new_elems;
|
||||
@@ -1031,8 +1016,8 @@ static llvm::Constant *MoveConstantIntoModule(
|
||||
llvm::cast<llvm::Constant>(it->get()), dest_module));
|
||||
}
|
||||
|
||||
return llvm::ConstantStruct::get(
|
||||
llvm::cast<llvm::StructType>(type), new_elems);
|
||||
return llvm::ConstantStruct::get(llvm::cast<llvm::StructType>(type),
|
||||
new_elems);
|
||||
|
||||
} else if (auto v = llvm::dyn_cast<llvm::ConstantVector>(ca); v) {
|
||||
std::vector<llvm::Constant *> new_elems;
|
||||
@@ -1045,27 +1030,23 @@ static llvm::Constant *MoveConstantIntoModule(
|
||||
return llvm::ConstantVector::get(new_elems);
|
||||
|
||||
} else if (in_same_context) {
|
||||
LOG(ERROR)
|
||||
<< "Unsupported CA when moving across module boundaries: "
|
||||
LOG(ERROR) << "Unsupported CA when moving across module boundaries: "
|
||||
<< LLVMThingToString(ce);
|
||||
return ca;
|
||||
|
||||
} else {
|
||||
LOG(FATAL)
|
||||
<< "Unsupported CA when moving across context boundaries: "
|
||||
LOG(FATAL) << "Unsupported CA when moving across context boundaries: "
|
||||
<< LLVMThingToString(ce);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} else if (in_same_context) {
|
||||
LOG(ERROR)
|
||||
<< "Unsupported constant when moving across module boundaries: "
|
||||
LOG(ERROR) << "Unsupported constant when moving across module boundaries: "
|
||||
<< LLVMThingToString(ce);
|
||||
return c;
|
||||
|
||||
} else {
|
||||
LOG(FATAL)
|
||||
<< "Unsupported constant when moving across context boundaries: "
|
||||
LOG(FATAL) << "Unsupported constant when moving across context boundaries: "
|
||||
<< LLVMThingToString(ce);
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1222,7 +1203,8 @@ void CloneFunctionInto(llvm::Function *source_func, llvm::Function *dest_func,
|
||||
as_func->setAttributes(global_val_func->getAttributes());
|
||||
}
|
||||
|
||||
} else if (auto global_val_var = llvm::dyn_cast<llvm::GlobalVariable>(global_val);
|
||||
} else if (auto global_val_var =
|
||||
llvm::dyn_cast<llvm::GlobalVariable>(global_val);
|
||||
global_val_var) {
|
||||
const auto new_global_val_var =
|
||||
llvm::dyn_cast<llvm::GlobalVariable>(dest_mod->getOrInsertGlobal(
|
||||
@@ -1328,9 +1310,8 @@ void MoveFunctionIntoModule(llvm::Function *func, llvm::Module *dest_module) {
|
||||
|
||||
namespace {
|
||||
|
||||
static llvm::Type *RecontextualizeType(
|
||||
llvm::Type *type,
|
||||
llvm::LLVMContext &context,
|
||||
static llvm::Type *
|
||||
RecontextualizeType(llvm::Type *type, llvm::LLVMContext &context,
|
||||
std::unordered_map<llvm::Type *, llvm::Type *> &cache) {
|
||||
auto &cached = cache[type];
|
||||
if (cached) {
|
||||
@@ -1338,51 +1319,40 @@ static llvm::Type *RecontextualizeType(
|
||||
}
|
||||
|
||||
switch (type->getTypeID()) {
|
||||
case llvm::Type::VoidTyID:
|
||||
return llvm::Type::getVoidTy(context);
|
||||
case llvm::Type::HalfTyID:
|
||||
return llvm::Type::getHalfTy(context);
|
||||
case llvm::Type::FloatTyID:
|
||||
return llvm::Type::getFloatTy(context);
|
||||
case llvm::Type::DoubleTyID:
|
||||
return llvm::Type::getDoubleTy(context);
|
||||
case llvm::Type::X86_FP80TyID:
|
||||
return llvm::Type::getX86_FP80Ty(context);
|
||||
case llvm::Type::FP128TyID:
|
||||
return llvm::Type::getFP128Ty(context);
|
||||
case llvm::Type::PPC_FP128TyID:
|
||||
return llvm::Type::getPPC_FP128Ty(context);
|
||||
case llvm::Type::LabelTyID:
|
||||
return llvm::Type::getLabelTy(context);
|
||||
case llvm::Type::MetadataTyID:
|
||||
return llvm::Type::getMetadataTy(context);
|
||||
case llvm::Type::X86_MMXTyID:
|
||||
return llvm::Type::getX86_MMXTy(context);
|
||||
case llvm::Type::TokenTyID:
|
||||
return llvm::Type::getTokenTy(context);
|
||||
case llvm::Type::VoidTyID: return llvm::Type::getVoidTy(context);
|
||||
case llvm::Type::HalfTyID: return llvm::Type::getHalfTy(context);
|
||||
case llvm::Type::FloatTyID: return llvm::Type::getFloatTy(context);
|
||||
case llvm::Type::DoubleTyID: return llvm::Type::getDoubleTy(context);
|
||||
case llvm::Type::X86_FP80TyID: return llvm::Type::getX86_FP80Ty(context);
|
||||
case llvm::Type::FP128TyID: return llvm::Type::getFP128Ty(context);
|
||||
case llvm::Type::PPC_FP128TyID: return llvm::Type::getPPC_FP128Ty(context);
|
||||
case llvm::Type::LabelTyID: return llvm::Type::getLabelTy(context);
|
||||
case llvm::Type::MetadataTyID: return llvm::Type::getMetadataTy(context);
|
||||
case llvm::Type::X86_MMXTyID: return llvm::Type::getX86_MMXTy(context);
|
||||
case llvm::Type::TokenTyID: return llvm::Type::getTokenTy(context);
|
||||
case llvm::Type::IntegerTyID: {
|
||||
auto int_type = llvm::dyn_cast<llvm::IntegerType>(type);
|
||||
cached = llvm::IntegerType::get(
|
||||
context, int_type->getPrimitiveSizeInBits());
|
||||
cached =
|
||||
llvm::IntegerType::get(context, int_type->getPrimitiveSizeInBits());
|
||||
break;
|
||||
}
|
||||
case llvm::Type::FunctionTyID: {
|
||||
auto func_type = llvm::dyn_cast<llvm::FunctionType>(type);
|
||||
auto ret_type = RecontextualizeType(
|
||||
func_type->getReturnType(), context, cache);
|
||||
auto ret_type =
|
||||
RecontextualizeType(func_type->getReturnType(), context, cache);
|
||||
llvm::SmallVector<llvm::Type *, 4> param_types;
|
||||
for (auto param_type : func_type->params()) {
|
||||
param_types.push_back(
|
||||
RecontextualizeType(param_type, context, cache));
|
||||
param_types.push_back(RecontextualizeType(param_type, context, cache));
|
||||
}
|
||||
cached = llvm::FunctionType::get(ret_type, param_types, func_type->isVarArg());
|
||||
cached =
|
||||
llvm::FunctionType::get(ret_type, param_types, func_type->isVarArg());
|
||||
break;
|
||||
}
|
||||
|
||||
case llvm::Type::StructTyID: {
|
||||
auto struct_type = llvm::dyn_cast<llvm::StructType>(type);
|
||||
auto new_struct_type = llvm::StructType::create(
|
||||
context, struct_type->getName());
|
||||
auto new_struct_type =
|
||||
llvm::StructType::create(context, struct_type->getName());
|
||||
cached = new_struct_type;
|
||||
|
||||
llvm::SmallVector<llvm::Type *, 4> elem_types;
|
||||
@@ -1400,8 +1370,8 @@ static llvm::Type *RecontextualizeType(
|
||||
case llvm::Type::ArrayTyID: {
|
||||
auto arr_type = llvm::dyn_cast<llvm::ArrayType>(type);
|
||||
auto elem_type = arr_type->getElementType();
|
||||
cached = llvm::ArrayType::get(
|
||||
RecontextualizeType(elem_type, context, cache),
|
||||
cached =
|
||||
llvm::ArrayType::get(RecontextualizeType(elem_type, context, cache),
|
||||
arr_type->getNumElements());
|
||||
break;
|
||||
}
|
||||
@@ -1409,8 +1379,8 @@ static llvm::Type *RecontextualizeType(
|
||||
case llvm::Type::PointerTyID: {
|
||||
auto ptr_type = llvm::dyn_cast<llvm::PointerType>(type);
|
||||
auto elem_type = ptr_type->getElementType();
|
||||
cached = llvm::PointerType::get(
|
||||
RecontextualizeType(elem_type, context, cache),
|
||||
cached =
|
||||
llvm::PointerType::get(RecontextualizeType(elem_type, context, cache),
|
||||
ptr_type->getAddressSpace());
|
||||
break;
|
||||
}
|
||||
@@ -1418,15 +1388,15 @@ static llvm::Type *RecontextualizeType(
|
||||
case llvm::Type::VectorTyID: {
|
||||
auto arr_type = llvm::dyn_cast<llvm::VectorType>(type);
|
||||
auto elem_type = arr_type->getElementType();
|
||||
cached = llvm::VectorType::get(
|
||||
RecontextualizeType(elem_type, context, cache),
|
||||
cached =
|
||||
llvm::VectorType::get(RecontextualizeType(elem_type, context, cache),
|
||||
arr_type->getNumElements());
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG(FATAL)
|
||||
<< "Unable to recontextualize type " << LLVMThingToString(type);
|
||||
LOG(FATAL) << "Unable to recontextualize type "
|
||||
<< LLVMThingToString(type);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1449,20 +1419,16 @@ llvm::Type *RecontextualizeType(llvm::Type *type, llvm::LLVMContext &context) {
|
||||
// memory, building up the correct type. This will invoke the various
|
||||
// memory read intrinsics in order to match the right type, or
|
||||
// recursively build up the right type.
|
||||
llvm::Value *LoadFromMemory(
|
||||
const IntrinsicTable &intrinsics,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Type *type,
|
||||
llvm::Value *mem_ptr,
|
||||
llvm::Value *addr) {
|
||||
llvm::Value *LoadFromMemory(const IntrinsicTable &intrinsics,
|
||||
llvm::BasicBlock *block, llvm::Type *type,
|
||||
llvm::Value *mem_ptr, llvm::Value *addr) {
|
||||
|
||||
const auto initial_addr = addr;
|
||||
auto module = intrinsics.error->getParent();
|
||||
auto &context = module->getContext();
|
||||
llvm::DataLayout dl(module);
|
||||
llvm::Value *args_2[2] = {mem_ptr, addr};
|
||||
auto index_type = llvm::Type::getIntNTy(
|
||||
context, dl.getPointerSizeInBits(0));
|
||||
auto index_type = llvm::Type::getIntNTy(context, dl.getPointerSizeInBits(0));
|
||||
|
||||
llvm::IRBuilder<> ir(block);
|
||||
|
||||
@@ -1483,13 +1449,11 @@ llvm::Value *LoadFromMemory(
|
||||
return ir.CreateCall(intrinsics.read_memory_f64, args_2);
|
||||
|
||||
case llvm::Type::X86_FP80TyID:
|
||||
return ir.CreateFPExt(
|
||||
ir.CreateCall(intrinsics.read_memory_f80, args_2),
|
||||
return ir.CreateFPExt(ir.CreateCall(intrinsics.read_memory_f80, args_2),
|
||||
type);
|
||||
|
||||
case llvm::Type::X86_MMXTyID:
|
||||
return ir.CreateBitCast(
|
||||
ir.CreateCall(intrinsics.read_memory_64, args_2),
|
||||
return ir.CreateBitCast(ir.CreateCall(intrinsics.read_memory_64, args_2),
|
||||
type);
|
||||
|
||||
case llvm::Type::IntegerTyID:
|
||||
@@ -1507,12 +1471,10 @@ llvm::Value *LoadFromMemory(
|
||||
const auto size = dl.getTypeAllocSize(type);
|
||||
auto res = ir.CreateAlloca(type);
|
||||
auto i8_type = llvm::Type::getInt8Ty(context);
|
||||
auto byte_array = ir.CreateBitCast(
|
||||
res, llvm::PointerType::get(i8_type, 0));
|
||||
auto byte_array =
|
||||
ir.CreateBitCast(res, llvm::PointerType::get(i8_type, 0));
|
||||
llvm::Value *gep_indices[2] = {
|
||||
llvm::ConstantInt::get(index_type, 0, false),
|
||||
nullptr
|
||||
};
|
||||
llvm::ConstantInt::get(index_type, 0, false), nullptr};
|
||||
|
||||
// Load one byte at a time from memory, and store it into
|
||||
// `res`.
|
||||
@@ -1538,11 +1500,10 @@ llvm::Value *LoadFromMemory(
|
||||
for (auto i = 0u; i < num_elems; ++i) {
|
||||
const auto elem_type = struct_type->getStructElementType(i);
|
||||
const auto offset = layout->getElementOffset(i);
|
||||
addr = ir.CreateAdd(
|
||||
initial_addr,
|
||||
llvm::ConstantInt::get(addr->getType(), offset, false));
|
||||
auto elem_val = LoadFromMemory(
|
||||
intrinsics, block, elem_type, mem_ptr, addr);
|
||||
addr = ir.CreateAdd(initial_addr, llvm::ConstantInt::get(
|
||||
addr->getType(), offset, false));
|
||||
auto elem_val =
|
||||
LoadFromMemory(intrinsics, block, elem_type, mem_ptr, addr);
|
||||
ir.SetInsertPoint(block);
|
||||
unsigned indexes[] = {i};
|
||||
val = ir.CreateInsertValue(val, elem_val, indexes);
|
||||
@@ -1558,15 +1519,13 @@ llvm::Value *LoadFromMemory(
|
||||
const auto elem_size = dl.getTypeAllocSize(elem_type);
|
||||
llvm::Value *val = llvm::UndefValue::get(type);
|
||||
|
||||
for (uint64_t index = 0, offset = 0;
|
||||
index < num_elems;
|
||||
for (uint64_t index = 0, offset = 0; index < num_elems;
|
||||
++index, offset += elem_size) {
|
||||
addr = ir.CreateAdd(
|
||||
initial_addr,
|
||||
llvm::ConstantInt::get(addr->getType(), offset, false));
|
||||
addr = ir.CreateAdd(initial_addr, llvm::ConstantInt::get(
|
||||
addr->getType(), offset, false));
|
||||
unsigned indexes[] = {static_cast<unsigned>(index)};
|
||||
auto elem_val = LoadFromMemory(
|
||||
intrinsics, block, elem_type, mem_ptr, addr);
|
||||
auto elem_val =
|
||||
LoadFromMemory(intrinsics, block, elem_type, mem_ptr, addr);
|
||||
ir.SetInsertPoint(block);
|
||||
val = ir.CreateInsertValue(val, elem_val, indexes);
|
||||
}
|
||||
@@ -1578,10 +1537,10 @@ llvm::Value *LoadFromMemory(
|
||||
case llvm::Type::PointerTyID: {
|
||||
auto ptr_type = llvm::dyn_cast<llvm::PointerType>(type);
|
||||
auto size_bits = dl.getTypeAllocSizeInBits(ptr_type);
|
||||
auto intptr_type = llvm::IntegerType::get(
|
||||
context, static_cast<unsigned>(size_bits));
|
||||
auto addr_val = LoadFromMemory(
|
||||
intrinsics, block, intptr_type, mem_ptr, addr);
|
||||
auto intptr_type =
|
||||
llvm::IntegerType::get(context, static_cast<unsigned>(size_bits));
|
||||
auto addr_val =
|
||||
LoadFromMemory(intrinsics, block, intptr_type, mem_ptr, addr);
|
||||
ir.SetInsertPoint(block);
|
||||
return ir.CreateIntToPtr(addr_val, ptr_type);
|
||||
}
|
||||
@@ -1594,17 +1553,15 @@ llvm::Value *LoadFromMemory(
|
||||
const auto elem_size = dl.getTypeAllocSize(elem_type);
|
||||
llvm::Value *val = llvm::UndefValue::get(type);
|
||||
|
||||
for (uint64_t index = 0, offset = 0;
|
||||
index < num_elems;
|
||||
for (uint64_t index = 0, offset = 0; index < num_elems;
|
||||
++index, offset += elem_size) {
|
||||
addr = ir.CreateAdd(
|
||||
initial_addr,
|
||||
llvm::ConstantInt::get(addr->getType(), offset, false));
|
||||
auto elem_val = LoadFromMemory(
|
||||
intrinsics, block, elem_type, mem_ptr, addr);
|
||||
addr = ir.CreateAdd(initial_addr, llvm::ConstantInt::get(
|
||||
addr->getType(), offset, false));
|
||||
auto elem_val =
|
||||
LoadFromMemory(intrinsics, block, elem_type, mem_ptr, addr);
|
||||
ir.SetInsertPoint(block);
|
||||
val = ir.CreateInsertElement(
|
||||
val, elem_val, static_cast<unsigned>(index));
|
||||
val =
|
||||
ir.CreateInsertElement(val, elem_val, static_cast<unsigned>(index));
|
||||
}
|
||||
return val;
|
||||
}
|
||||
@@ -1615,8 +1572,7 @@ llvm::Value *LoadFromMemory(
|
||||
case llvm::Type::TokenTyID:
|
||||
case llvm::Type::FunctionTyID:
|
||||
default:
|
||||
LOG(FATAL)
|
||||
<< "Unable to produce IR sequence to load type "
|
||||
LOG(FATAL) << "Unable to produce IR sequence to load type "
|
||||
<< remill::LLVMThingToString(type) << " from memory";
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1628,12 +1584,9 @@ llvm::Value *LoadFromMemory(
|
||||
// the type into components which can be written to memory.
|
||||
//
|
||||
// Returns the new value of the memory pointer.
|
||||
llvm::Value *StoreToMemory(
|
||||
const IntrinsicTable &intrinsics,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Value *val_to_store,
|
||||
llvm::Value *mem_ptr,
|
||||
llvm::Value *addr) {
|
||||
llvm::Value *StoreToMemory(const IntrinsicTable &intrinsics,
|
||||
llvm::BasicBlock *block, llvm::Value *val_to_store,
|
||||
llvm::Value *mem_ptr, llvm::Value *addr) {
|
||||
|
||||
const auto initial_addr = addr;
|
||||
auto module = intrinsics.error->getParent();
|
||||
@@ -1696,12 +1649,10 @@ llvm::Value *StoreToMemory(
|
||||
ir.CreateStore(val_to_store, res);
|
||||
|
||||
auto i8_type = llvm::Type::getInt8Ty(context);
|
||||
auto byte_array = ir.CreateBitCast(
|
||||
res, llvm::PointerType::get(i8_type, 0));
|
||||
auto byte_array =
|
||||
ir.CreateBitCast(res, llvm::PointerType::get(i8_type, 0));
|
||||
llvm::Value *gep_indices[2] = {
|
||||
llvm::ConstantInt::get(index_type, 0, false),
|
||||
nullptr
|
||||
};
|
||||
llvm::ConstantInt::get(index_type, 0, false), nullptr};
|
||||
|
||||
// Store one byte at a time to memory.
|
||||
for (auto i = 0U; i < size; ++i) {
|
||||
@@ -1728,8 +1679,8 @@ llvm::Value *StoreToMemory(
|
||||
llvm::ConstantInt::get(addr->getType(), offset, false));
|
||||
unsigned indexes[] = {i};
|
||||
const auto elem_val = ir.CreateExtractValue(val_to_store, indexes);
|
||||
mem_ptr = StoreToMemory(
|
||||
intrinsics, block, elem_val, mem_ptr, elem_addr);
|
||||
mem_ptr =
|
||||
StoreToMemory(intrinsics, block, elem_val, mem_ptr, elem_addr);
|
||||
ir.SetInsertPoint(block);
|
||||
}
|
||||
return mem_ptr;
|
||||
@@ -1742,8 +1693,7 @@ llvm::Value *StoreToMemory(
|
||||
const auto elem_type = arr_type->getElementType();
|
||||
const auto elem_size = dl.getTypeAllocSize(elem_type);
|
||||
|
||||
for (uint64_t index = 0, offset = 0;
|
||||
index < num_elems;
|
||||
for (uint64_t index = 0, offset = 0; index < num_elems;
|
||||
++index, offset += elem_size) {
|
||||
|
||||
auto elem_addr = ir.CreateAdd(
|
||||
@@ -1751,8 +1701,8 @@ llvm::Value *StoreToMemory(
|
||||
llvm::ConstantInt::get(addr->getType(), offset, false));
|
||||
unsigned indexes[] = {static_cast<unsigned>(index)};
|
||||
auto elem_val = ir.CreateExtractValue(val_to_store, indexes);
|
||||
mem_ptr = StoreToMemory(
|
||||
intrinsics, block, elem_val, mem_ptr, elem_addr);
|
||||
mem_ptr =
|
||||
StoreToMemory(intrinsics, block, elem_val, mem_ptr, elem_addr);
|
||||
ir.SetInsertPoint(block);
|
||||
offset += elem_size;
|
||||
index += 1;
|
||||
@@ -1765,10 +1715,9 @@ llvm::Value *StoreToMemory(
|
||||
case llvm::Type::PointerTyID: {
|
||||
auto ptr_type = llvm::dyn_cast<llvm::PointerType>(type);
|
||||
auto size_bits = dl.getTypeAllocSizeInBits(ptr_type);
|
||||
auto intptr_type = llvm::IntegerType::get(
|
||||
context, static_cast<unsigned>(size_bits));
|
||||
return StoreToMemory(
|
||||
intrinsics, block,
|
||||
auto intptr_type =
|
||||
llvm::IntegerType::get(context, static_cast<unsigned>(size_bits));
|
||||
return StoreToMemory(intrinsics, block,
|
||||
ir.CreatePtrToInt(val_to_store, intptr_type),
|
||||
mem_ptr, addr);
|
||||
}
|
||||
@@ -1780,17 +1729,16 @@ llvm::Value *StoreToMemory(
|
||||
const auto elem_type = vec_type->getElementType();
|
||||
const auto elem_size = dl.getTypeAllocSize(elem_type);
|
||||
|
||||
for (uint64_t index = 0, offset = 0;
|
||||
index < num_elems;
|
||||
for (uint64_t index = 0, offset = 0; index < num_elems;
|
||||
++index, offset += elem_size) {
|
||||
|
||||
auto elem_addr = ir.CreateAdd(
|
||||
initial_addr,
|
||||
llvm::ConstantInt::get(addr->getType(), offset, false));
|
||||
auto elem_val = ir.CreateExtractElement(
|
||||
val_to_store, static_cast<unsigned>(index));
|
||||
mem_ptr = StoreToMemory(
|
||||
intrinsics, block, elem_val, mem_ptr, elem_addr);
|
||||
auto elem_val =
|
||||
ir.CreateExtractElement(val_to_store, static_cast<unsigned>(index));
|
||||
mem_ptr =
|
||||
StoreToMemory(intrinsics, block, elem_val, mem_ptr, elem_addr);
|
||||
ir.SetInsertPoint(block);
|
||||
offset += elem_size;
|
||||
index += 1;
|
||||
@@ -1805,8 +1753,7 @@ llvm::Value *StoreToMemory(
|
||||
case llvm::Type::TokenTyID:
|
||||
case llvm::Type::FunctionTyID:
|
||||
default:
|
||||
LOG(FATAL)
|
||||
<< "Unable to produce IR sequence to store type "
|
||||
LOG(FATAL) << "Unable to produce IR sequence to store type "
|
||||
<< remill::LLVMThingToString(type) << " to memory";
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1848,8 +1795,8 @@ BuildIndexes(const llvm::DataLayout &dl, llvm::Type *type, size_t offset,
|
||||
// Indexing into the `i`th element.
|
||||
} else if ((offset + elem_offset) <= goal_offset) {
|
||||
indexes_out.push_back(llvm::ConstantInt::get(index_type, i, false));
|
||||
return BuildIndexes(
|
||||
dl, elem_type, offset + elem_offset, goal_offset, indexes_out);
|
||||
return BuildIndexes(dl, elem_type, offset + elem_offset, goal_offset,
|
||||
indexes_out);
|
||||
|
||||
// We're indexing into some padding before the current element.
|
||||
} else if (i) {
|
||||
@@ -1876,10 +1823,8 @@ BuildIndexes(const llvm::DataLayout &dl, llvm::Type *type, size_t offset,
|
||||
CHECK_LE(offset, goal_offset);
|
||||
CHECK_LE(goal_offset, (offset + elem_size));
|
||||
|
||||
indexes_out.push_back(
|
||||
llvm::ConstantInt::get(index_type, index, false));
|
||||
return BuildIndexes(
|
||||
dl, elem_type, offset, goal_offset, indexes_out);
|
||||
indexes_out.push_back(llvm::ConstantInt::get(index_type, index, false));
|
||||
return BuildIndexes(dl, elem_type, offset, goal_offset, indexes_out);
|
||||
}
|
||||
|
||||
return {offset, type};
|
||||
@@ -1889,9 +1834,9 @@ BuildIndexes(const llvm::DataLayout &dl, llvm::Type *type, size_t offset,
|
||||
// build either a constant expression or sequence of instructions that can
|
||||
// index to that offset. `ir` is provided to support the instruction case
|
||||
// and to give access to a module for data layouts.
|
||||
llvm::Value *BuildPointerToOffset(
|
||||
llvm::IRBuilder<> &ir, llvm::Value *ptr,
|
||||
size_t dest_elem_offset, llvm::Type *dest_ptr_type_) {
|
||||
llvm::Value *BuildPointerToOffset(llvm::IRBuilder<> &ir, llvm::Value *ptr,
|
||||
size_t dest_elem_offset,
|
||||
llvm::Type *dest_ptr_type_) {
|
||||
|
||||
const auto block = ir.GetInsertBlock();
|
||||
const auto module = block->getModule();
|
||||
@@ -1903,7 +1848,8 @@ llvm::Value *BuildPointerToOffset(
|
||||
|
||||
auto ptr_type = llvm::dyn_cast<llvm::PointerType>(ptr->getType());
|
||||
CHECK_NOTNULL(ptr_type);
|
||||
const auto dest_elem_ptr_type = llvm::dyn_cast<llvm::PointerType>(dest_ptr_type_);
|
||||
const auto dest_elem_ptr_type =
|
||||
llvm::dyn_cast<llvm::PointerType>(dest_ptr_type_);
|
||||
CHECK_NOTNULL(dest_elem_ptr_type);
|
||||
auto ptr_addr_space = ptr_type->getAddressSpace();
|
||||
const auto dest_ptr_addr_space = dest_elem_ptr_type->getAddressSpace();
|
||||
@@ -1911,15 +1857,13 @@ llvm::Value *BuildPointerToOffset(
|
||||
|
||||
// Change address spaces if necessary before indexing.
|
||||
if (dest_ptr_addr_space != ptr_addr_space) {
|
||||
ptr_type = llvm::PointerType::get(
|
||||
ptr_type->getPointerElementType(),
|
||||
ptr_type = llvm::PointerType::get(ptr_type->getPointerElementType(),
|
||||
dest_ptr_addr_space);
|
||||
ptr_addr_space = dest_ptr_addr_space;
|
||||
|
||||
if (constant_ptr) {
|
||||
constant_ptr = llvm::ConstantExpr::getAddrSpaceCast(
|
||||
constant_ptr,
|
||||
ptr_type);
|
||||
constant_ptr =
|
||||
llvm::ConstantExpr::getAddrSpaceCast(constant_ptr, ptr_type);
|
||||
ptr = constant_ptr;
|
||||
} else {
|
||||
ptr = ir.CreateAddrSpaceCast(ptr, ptr_type);
|
||||
@@ -1935,8 +1879,8 @@ llvm::Value *BuildPointerToOffset(
|
||||
|
||||
dest_elem_offset = dest_elem_offset % ptr_elem_size;
|
||||
|
||||
auto [reached_disp, indexed_type] = BuildIndexes(
|
||||
dl, ptr_elem_type, 0, dest_elem_offset, indexes);
|
||||
auto [reached_disp, indexed_type] =
|
||||
BuildIndexes(dl, ptr_elem_type, 0, dest_elem_offset, indexes);
|
||||
|
||||
if (reached_disp) {
|
||||
if (constant_ptr) {
|
||||
@@ -1962,36 +1906,36 @@ llvm::Value *BuildPointerToOffset(
|
||||
DCHECK_LT(diff, dest_elem_offset);
|
||||
DCHECK_LT(diff, dl.getTypeAllocSize(indexed_type));
|
||||
const auto i8_type = llvm::Type::getInt8Ty(context);
|
||||
const auto i8_ptr_type = llvm::PointerType::getInt8PtrTy(
|
||||
context, ptr_addr_space);
|
||||
const auto i8_ptr_type =
|
||||
llvm::PointerType::getInt8PtrTy(context, ptr_addr_space);
|
||||
|
||||
const auto dest_elem_size = dl.getTypeAllocSize(dest_elem_type);
|
||||
if (diff % dest_elem_size) {
|
||||
if (constant_ptr) {
|
||||
constant_ptr = llvm::ConstantExpr::getBitCast(
|
||||
constant_ptr, i8_ptr_type);
|
||||
constant_ptr =
|
||||
llvm::ConstantExpr::getBitCast(constant_ptr, i8_ptr_type);
|
||||
constant_ptr = llvm::ConstantExpr::getGetElementPtr(
|
||||
i8_type, constant_ptr, llvm::ConstantInt::get(i32_type, diff));
|
||||
return llvm::ConstantExpr::getBitCast(constant_ptr, dest_elem_ptr_type);
|
||||
|
||||
} else {
|
||||
ptr = ir.CreateBitCast(ptr, i8_ptr_type);
|
||||
ptr = ir.CreateGEP(
|
||||
i8_type, ptr, llvm::ConstantInt::get(i32_type, diff, false));
|
||||
ptr = ir.CreateGEP(i8_type, ptr,
|
||||
llvm::ConstantInt::get(i32_type, diff, false));
|
||||
return ir.CreateBitCast(ptr, dest_elem_ptr_type);
|
||||
}
|
||||
} else {
|
||||
if (constant_ptr) {
|
||||
constant_ptr = llvm::ConstantExpr::getBitCast(
|
||||
constant_ptr, dest_elem_ptr_type);
|
||||
constant_ptr =
|
||||
llvm::ConstantExpr::getBitCast(constant_ptr, dest_elem_ptr_type);
|
||||
return llvm::ConstantExpr::getGetElementPtr(
|
||||
dest_elem_type, constant_ptr,
|
||||
llvm::ConstantInt::get(i32_type, diff / dest_elem_size));
|
||||
} else {
|
||||
ptr = ir.CreateBitCast(ptr, dest_elem_ptr_type);
|
||||
return ir.CreateGEP(
|
||||
dest_elem_type,
|
||||
ptr, llvm::ConstantInt::get(i32_type, diff / dest_elem_size, false));
|
||||
dest_elem_type, ptr,
|
||||
llvm::ConstantInt::get(i32_type, diff / dest_elem_size, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2005,8 +1949,9 @@ llvm::Value *BuildPointerToOffset(
|
||||
|
||||
|
||||
// Compute the total offset of a GEP chain.
|
||||
std::pair<llvm::Value *, int64_t> StripAndAccumulateConstantOffsets(
|
||||
const llvm::DataLayout &dl, llvm::Value *base) {
|
||||
std::pair<llvm::Value *, int64_t>
|
||||
StripAndAccumulateConstantOffsets(const llvm::DataLayout &dl,
|
||||
llvm::Value *base) {
|
||||
const auto ptr_size = dl.getPointerSizeInBits(0);
|
||||
int64_t total_offset = 0;
|
||||
while (base) {
|
||||
@@ -2032,7 +1977,6 @@ std::pair<llvm::Value *, int64_t> StripAndAccumulateConstantOffsets(
|
||||
|
||||
} else {
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
return {base, total_offset};
|
||||
|
||||
+37
-47
@@ -16,17 +16,17 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <llvm/ADT/SmallVector.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "remill/BC/ABI.h"
|
||||
|
||||
namespace llvm {
|
||||
@@ -54,8 +54,7 @@ class IntrinsicTable;
|
||||
void InitFunctionAttributes(llvm::Function *F);
|
||||
|
||||
// Create a call from one lifted function to another.
|
||||
llvm::CallInst *AddCall(llvm::BasicBlock *source_block,
|
||||
llvm::Value *dest_func);
|
||||
llvm::CallInst *AddCall(llvm::BasicBlock *source_block, llvm::Value *dest_func);
|
||||
|
||||
// Create a tail-call from one lifted function to another.
|
||||
llvm::CallInst *AddTerminatingTailCall(llvm::Function *source_func,
|
||||
@@ -66,14 +65,12 @@ llvm::CallInst *AddTerminatingTailCall(llvm::BasicBlock *source_block,
|
||||
|
||||
// Find a local variable defined in the entry block of the function. We use
|
||||
// this to find register variables.
|
||||
llvm::Value *FindVarInFunction(llvm::BasicBlock *block,
|
||||
const std::string &name,
|
||||
llvm::Value *FindVarInFunction(llvm::BasicBlock *block, const std::string &name,
|
||||
bool allow_failure = false);
|
||||
|
||||
// Find a local variable defined in the entry block of the function. We use
|
||||
// this to find register variables.
|
||||
llvm::Value *FindVarInFunction(llvm::Function *func,
|
||||
const std::string &name,
|
||||
llvm::Value *FindVarInFunction(llvm::Function *func, const std::string &name,
|
||||
bool allow_failure = false);
|
||||
|
||||
// Find the machine state pointer. The machine state pointer is, by convention,
|
||||
@@ -134,37 +131,35 @@ llvm::GlobalVariable *FindGlobaVariable(llvm::Module *M,
|
||||
bool VerifyModule(llvm::Module *module);
|
||||
|
||||
// Parses and loads a bitcode file into memory.
|
||||
std::unique_ptr<llvm::Module> LoadModuleFromFile(
|
||||
llvm::LLVMContext *context, const std::string &file_name,
|
||||
std::unique_ptr<llvm::Module> LoadModuleFromFile(llvm::LLVMContext *context,
|
||||
const std::string &file_name,
|
||||
bool allow_failure = false);
|
||||
|
||||
// Loads the semantics for the "host" machine, i.e. the machine that this
|
||||
// remill is compiled on.
|
||||
std::unique_ptr<llvm::Module> LoadHostSemantics(
|
||||
llvm::LLVMContext &context) __attribute__((deprecated));
|
||||
std::unique_ptr<llvm::Module> LoadHostSemantics(llvm::LLVMContext &context)
|
||||
__attribute__((deprecated));
|
||||
|
||||
// Loads the semantics for the "target" machine, i.e. the machine of the
|
||||
// code that we want to lift.
|
||||
std::unique_ptr<llvm::Module> LoadTargetSemantics(
|
||||
llvm::LLVMContext &context) __attribute__((deprecated));
|
||||
std::unique_ptr<llvm::Module> LoadTargetSemantics(llvm::LLVMContext &context)
|
||||
__attribute__((deprecated));
|
||||
|
||||
// Loads the semantics for the `arch`-specific machine, i.e. the machine of the
|
||||
// code that we want to lift.
|
||||
std::unique_ptr<llvm::Module> LoadArchSemantics(const Arch *arch);
|
||||
|
||||
inline std::unique_ptr<llvm::Module> LoadArchSemantics(
|
||||
const std::unique_ptr<const Arch> &arch) {
|
||||
inline std::unique_ptr<llvm::Module>
|
||||
LoadArchSemantics(const std::unique_ptr<const Arch> &arch) {
|
||||
return LoadArchSemantics(arch.get());
|
||||
}
|
||||
|
||||
// Store an LLVM module into a file.
|
||||
bool StoreModuleToFile(llvm::Module *module,
|
||||
const std::string &file_name,
|
||||
bool StoreModuleToFile(llvm::Module *module, const std::string &file_name,
|
||||
bool allow_failure = false);
|
||||
|
||||
// Store a module, serialized to LLVM IR, into a file.
|
||||
bool StoreModuleIRToFile(llvm::Module *module,
|
||||
const std::string &file_name,
|
||||
bool StoreModuleIRToFile(llvm::Module *module, const std::string &file_name,
|
||||
bool allow_failure = false);
|
||||
|
||||
// Find the path to the semantics bitcode file associated with `FLAGS_arch`.
|
||||
@@ -188,15 +183,16 @@ llvm::FunctionType *LiftedFunctionType(llvm::Module *module);
|
||||
|
||||
// Return a vector of arguments to pass to a lifted function, where the
|
||||
// arguments are derived from `block`.
|
||||
std::array<llvm::Value *, kNumBlockArgs> LiftedFunctionArgs(llvm::BasicBlock *block);
|
||||
std::array<llvm::Value *, kNumBlockArgs>
|
||||
LiftedFunctionArgs(llvm::BasicBlock *block);
|
||||
|
||||
// Serialize an LLVM object into a string.
|
||||
std::string LLVMThingToString(llvm::Value *thing);
|
||||
std::string LLVMThingToString(llvm::Type *thing);
|
||||
|
||||
// Apply a callback function to every semantics bitcode function.
|
||||
using ISelCallback = std::function<
|
||||
void(llvm::GlobalVariable *, llvm::Function *)>;
|
||||
using ISelCallback =
|
||||
std::function<void(llvm::GlobalVariable *, llvm::Function *)>;
|
||||
void ForEachISel(llvm::Module *module, ISelCallback callback);
|
||||
|
||||
// Declare a lifted function of the correct type.
|
||||
@@ -220,8 +216,7 @@ using ValueMap = std::unordered_map<llvm::Value *, llvm::Value *>;
|
||||
//
|
||||
// Note: this will try to clone globals referenced from the module of
|
||||
// `source_func` into the module of `dest_func`.
|
||||
void CloneFunctionInto(llvm::Function *source_func,
|
||||
llvm::Function *dest_func,
|
||||
void CloneFunctionInto(llvm::Function *source_func, llvm::Function *dest_func,
|
||||
ValueMap &value_map);
|
||||
|
||||
// Clone function `source_func` into `dest_func`. This will strip out debug
|
||||
@@ -253,12 +248,9 @@ llvm::Type *RecontextualizeType(llvm::Type *type, llvm::LLVMContext &context);
|
||||
// recursively build up the right type.
|
||||
//
|
||||
// Returns the loaded value.
|
||||
llvm::Value *LoadFromMemory(
|
||||
const IntrinsicTable &intrinsics,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Type *type,
|
||||
llvm::Value *mem_ptr,
|
||||
llvm::Value *addr);
|
||||
llvm::Value *LoadFromMemory(const IntrinsicTable &intrinsics,
|
||||
llvm::BasicBlock *block, llvm::Type *type,
|
||||
llvm::Value *mem_ptr, llvm::Value *addr);
|
||||
|
||||
// Produce a sequence of instructions that will store a value to
|
||||
// memory. This will invoke the various memory write intrinsics
|
||||
@@ -266,12 +258,9 @@ llvm::Value *LoadFromMemory(
|
||||
// the type into components which can be written to memory.
|
||||
//
|
||||
// Returns the new value of the memory pointer.
|
||||
llvm::Value *StoreToMemory(
|
||||
const IntrinsicTable &intrinsics,
|
||||
llvm::BasicBlock *block,
|
||||
llvm::Value *val_to_store,
|
||||
llvm::Value *mem_ptr,
|
||||
llvm::Value *addr);
|
||||
llvm::Value *StoreToMemory(const IntrinsicTable &intrinsics,
|
||||
llvm::BasicBlock *block, llvm::Value *val_to_store,
|
||||
llvm::Value *mem_ptr, llvm::Value *addr);
|
||||
|
||||
// Create an array of index values to pass to a GetElementPtr instruction
|
||||
// that will let us locate a particular register. Returns the final offset
|
||||
@@ -286,12 +275,13 @@ BuildIndexes(const llvm::DataLayout &dl, llvm::Type *type, size_t offset,
|
||||
// build either a constant expression or sequence of instructions that can
|
||||
// index to that offset. `ir` is provided to support the instruction case
|
||||
// and to give access to a module for data layouts.
|
||||
llvm::Value *BuildPointerToOffset(
|
||||
llvm::IRBuilder<> &ir, llvm::Value *ptr,
|
||||
size_t dest_elem_offset, llvm::Type *dest_ptr_type);
|
||||
llvm::Value *BuildPointerToOffset(llvm::IRBuilder<> &ir, llvm::Value *ptr,
|
||||
size_t dest_elem_offset,
|
||||
llvm::Type *dest_ptr_type);
|
||||
|
||||
// Compute the total offset of a GEP chain.
|
||||
std::pair<llvm::Value *, int64_t> StripAndAccumulateConstantOffsets(
|
||||
const llvm::DataLayout &dl, llvm::Value *base);
|
||||
std::pair<llvm::Value *, int64_t>
|
||||
StripAndAccumulateConstantOffsets(const llvm::DataLayout &dl,
|
||||
llvm::Value *base);
|
||||
|
||||
} // namespace remill
|
||||
|
||||
+2
-4
@@ -20,8 +20,7 @@
|
||||
|
||||
#define LLVM_VERSION(major, minor) ((major * 100) + minor)
|
||||
|
||||
#define LLVM_VERSION_NUMBER \
|
||||
LLVM_VERSION(LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR)
|
||||
#define LLVM_VERSION_NUMBER LLVM_VERSION(LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR)
|
||||
|
||||
#if LLVM_VERSION_NUMBER < LLVM_VERSION(3, 5)
|
||||
# error "Minimum supported LLVM version is 3.5"
|
||||
@@ -171,8 +170,7 @@
|
||||
# define _IF_LLVM_GTE_1000(...) , __VA_ARGS__
|
||||
#endif
|
||||
|
||||
#define IF_LLVM_LT(major, minor, ...) \
|
||||
IF_LLVM_LT_ ## major ## minor ## 0(__VA_ARGS__)
|
||||
#define IF_LLVM_LT(major, minor, ...) IF_LLVM_LT_##major##minor##0(__VA_ARGS__)
|
||||
|
||||
#define IF_LLVM_LT_(major, minor, ...) \
|
||||
IF_LLVM_LT_##major##minor##0##_(__VA_ARGS__)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if !defined(_WIN32)
|
||||
|
||||
// These headers are not present on a Windows build
|
||||
// and seem to be not needed.
|
||||
//
|
||||
@@ -28,8 +29,8 @@
|
||||
// _WIN32 Defined as 1 when the compilation target is 32-bit ARM, 64-bit
|
||||
// ARM, x86, or x64. Otherwise, undefined.
|
||||
# include <sys/param.h>
|
||||
# include <unistd.h>
|
||||
# include <sys/time.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
@@ -68,8 +69,7 @@ int futimens(int fd, const struct timespec times[2]) {
|
||||
auto last_access = &(times[0]);
|
||||
auto last_modified = &(times[1]);
|
||||
|
||||
auto need_now = !times ||
|
||||
last_access->tv_nsec == UTIME_NOW ||
|
||||
auto need_now = !times || last_access->tv_nsec == UTIME_NOW ||
|
||||
last_modified->tv_nsec == UTIME_NOW;
|
||||
|
||||
struct timespec curr_last_access = {};
|
||||
|
||||
+36
-40
@@ -20,8 +20,8 @@
|
||||
#include <cerrno>
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#ifndef WIN32
|
||||
# include <dirent.h>
|
||||
@@ -73,13 +73,20 @@ struct WIN32_FIND_DATA {
|
||||
char cAlternateFileName[14];
|
||||
};
|
||||
|
||||
extern "C" int CreateDirectoryA(const char *path_name, void *security_attributes);
|
||||
extern "C" std::uint32_t GetCurrentDirectoryA(std::uint32_t buffer_length, char *buffer);
|
||||
extern "C" int CreateDirectoryA(const char *path_name,
|
||||
void *security_attributes);
|
||||
extern "C" std::uint32_t GetCurrentDirectoryA(std::uint32_t buffer_length,
|
||||
char *buffer);
|
||||
extern "C" std::uint32_t GetFileAttributesA(const char *file_name);
|
||||
extern "C" int CopyFileA(const char *existing_file_name, const char *new_file_name, int file_if_exists);
|
||||
extern "C" int CreateHardLinkA(const char *file_name, const char *existing_file_name, void *security_attributes);
|
||||
extern "C" std::uint32_t FindFirstFileA(const char *file_name, WIN32_FIND_DATA *find_data);
|
||||
extern "C" std::uint32_t FindNextFileA(std::uint32_t handle, WIN32_FIND_DATA *find_data);
|
||||
extern "C" int CopyFileA(const char *existing_file_name,
|
||||
const char *new_file_name, int file_if_exists);
|
||||
extern "C" int CreateHardLinkA(const char *file_name,
|
||||
const char *existing_file_name,
|
||||
void *security_attributes);
|
||||
extern "C" std::uint32_t FindFirstFileA(const char *file_name,
|
||||
WIN32_FIND_DATA *find_data);
|
||||
extern "C" std::uint32_t FindNextFileA(std::uint32_t handle,
|
||||
WIN32_FIND_DATA *find_data);
|
||||
extern "C" int FindClose(std::uint32_t handle);
|
||||
extern "C" std::uint32_t GetLastError();
|
||||
|
||||
@@ -108,7 +115,7 @@ int link(const char *path1, const char *path2) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
namespace remill {
|
||||
@@ -184,8 +191,7 @@ bool FileExists(const std::string &path) {
|
||||
|
||||
struct stat64 file_info = {};
|
||||
return stat64(path.c_str(), &file_info) == 0 &&
|
||||
(S_ISREG(file_info.st_mode) ||
|
||||
S_ISFIFO(file_info.st_mode));
|
||||
(S_ISREG(file_info.st_mode) || S_ISFIFO(file_info.st_mode));
|
||||
}
|
||||
|
||||
uint64_t FileSize(int fd) {
|
||||
@@ -214,8 +220,7 @@ void ForEachFileInDirectory(const std::string &dir_name,
|
||||
DirectoryVisitor visitor) {
|
||||
std::vector<std::string> paths;
|
||||
auto dir = opendir(dir_name.c_str());
|
||||
CHECK(dir != nullptr)
|
||||
<< "Could not list the " << dir_name << " directory";
|
||||
CHECK(dir != nullptr) << "Could not list the " << dir_name << " directory";
|
||||
|
||||
while (auto ent = readdir(dir)) {
|
||||
if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
|
||||
@@ -246,8 +251,8 @@ bool TryCreateDirectory(const std::string &dir_name) {
|
||||
std::string CurrentWorkingDirectory(void) {
|
||||
char result[PATH_MAX] = {};
|
||||
auto res = getcwd(result, PATH_MAX);
|
||||
CHECK(res)
|
||||
<< "Could not determine current working directory: " << strerror(errno);
|
||||
CHECK(res) << "Could not determine current working directory: "
|
||||
<< strerror(errno);
|
||||
return std::string(result);
|
||||
}
|
||||
|
||||
@@ -259,9 +264,8 @@ bool RenameFile(const std::string &from_path, const std::string &to_path) {
|
||||
auto ret = rename(from_path.c_str(), to_path.c_str());
|
||||
auto err = errno;
|
||||
if (-1 == ret) {
|
||||
LOG(ERROR)
|
||||
<< "Unable to rename " << from_path << " to " << to_path
|
||||
<< ": " << strerror(err);
|
||||
LOG(ERROR) << "Unable to rename " << from_path << " to " << to_path << ": "
|
||||
<< strerror(err);
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
@@ -270,9 +274,7 @@ bool RenameFile(const std::string &from_path, const std::string &to_path) {
|
||||
|
||||
#ifndef WIN32
|
||||
namespace {
|
||||
enum : size_t {
|
||||
kCopyDataSize = 4096ULL
|
||||
};
|
||||
enum : size_t { kCopyDataSize = 4096ULL };
|
||||
|
||||
static uint8_t gCopyData[kCopyDataSize];
|
||||
} // namespace
|
||||
@@ -281,9 +283,8 @@ static uint8_t gCopyData[kCopyDataSize];
|
||||
#ifdef WIN32
|
||||
void CopyFile(const std::string &from_path, const std::string &to_path) {
|
||||
if (CopyFileA(from_path.data(), to_path.data(), false) == 0) {
|
||||
LOG(FATAL)
|
||||
<< "Unable to copy all data read from " << from_path
|
||||
<< " to " << to_path;
|
||||
LOG(FATAL) << "Unable to copy all data read from " << from_path << " to "
|
||||
<< to_path;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,28 +292,26 @@ void CopyFile(const std::string &from_path, const std::string &to_path) {
|
||||
void CopyFile(const std::string &from_path, const std::string &to_path) {
|
||||
unlink(to_path.c_str());
|
||||
auto from_fd = open(from_path.c_str(), O_RDONLY);
|
||||
CHECK(-1 != from_fd)
|
||||
<< "Unable to open source file " << from_path
|
||||
CHECK(-1 != from_fd) << "Unable to open source file " << from_path
|
||||
<< " for copying: " << strerror(errno);
|
||||
|
||||
auto to_fd = open(to_path.c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0666);
|
||||
CHECK(-1 != to_fd)
|
||||
<< "Unable to open destination file " << to_path
|
||||
CHECK(-1 != to_fd) << "Unable to open destination file " << to_path
|
||||
<< " for copying: " << strerror(errno);
|
||||
|
||||
auto file_size = FileSize(from_path);
|
||||
int errno_copy = 0;
|
||||
|
||||
do {
|
||||
auto num_read = read(
|
||||
from_fd, &(gCopyData[0]), std::min<size_t>(kCopyDataSize, file_size));
|
||||
auto num_read = read(from_fd, &(gCopyData[0]),
|
||||
std::min<size_t>(kCopyDataSize, file_size));
|
||||
if (-1 == num_read) {
|
||||
errno_copy = errno;
|
||||
break;
|
||||
}
|
||||
|
||||
auto num_written = write(
|
||||
to_fd, &(gCopyData[0]), static_cast<size_t>(num_read));
|
||||
auto num_written =
|
||||
write(to_fd, &(gCopyData[0]), static_cast<size_t>(num_read));
|
||||
|
||||
if (num_written != num_read) {
|
||||
errno_copy = errno;
|
||||
@@ -327,9 +326,8 @@ void CopyFile(const std::string &from_path, const std::string &to_path) {
|
||||
|
||||
if (errno_copy) {
|
||||
unlink(to_path.c_str());
|
||||
LOG(FATAL)
|
||||
<< "Unable to copy all data read from " << from_path
|
||||
<< " to " << to_path << ": " << strerror(errno_copy);
|
||||
LOG(FATAL) << "Unable to copy all data read from " << from_path << " to "
|
||||
<< to_path << ": " << strerror(errno_copy);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -341,9 +339,8 @@ void HardLinkOrCopyFile(const std::string &from_path,
|
||||
return;
|
||||
}
|
||||
|
||||
DLOG(WARNING)
|
||||
<< "Unable to link " << to_path << " to "
|
||||
<< from_path << ": " << strerror(errno);
|
||||
DLOG(WARNING) << "Unable to link " << to_path << " to " << from_path << ": "
|
||||
<< strerror(errno);
|
||||
|
||||
CopyFile(from_path, to_path);
|
||||
}
|
||||
@@ -365,9 +362,8 @@ std::string CanonicalPath(const std::string &path) {
|
||||
auto err = errno;
|
||||
#endif
|
||||
if (!canon_path_c) {
|
||||
DLOG(WARNING)
|
||||
<< "Cannot compute full path of " << path
|
||||
<< ": " << strerror(err);
|
||||
DLOG(WARNING) << "Cannot compute full path of " << path << ": "
|
||||
<< strerror(err);
|
||||
return path;
|
||||
} else {
|
||||
std::string canon_path(canon_path_c);
|
||||
|
||||
+18
-32
@@ -14,41 +14,32 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <glog/logging.h>
|
||||
#include <gflags/gflags.h>
|
||||
|
||||
#include "remill/OS/OS.h"
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
#include <llvm/ADT/Triple.h>
|
||||
|
||||
DEFINE_string(os, REMILL_OS, "Operating system name of the code being "
|
||||
DEFINE_string(os, REMILL_OS,
|
||||
"Operating system name of the code being "
|
||||
"translated. Valid OSes: linux, macos, windows, solaris.");
|
||||
|
||||
namespace remill {
|
||||
|
||||
OSName GetOSName(const llvm::Triple &triple) {
|
||||
switch (triple.getOS()) {
|
||||
case llvm::Triple::OSType::MacOSX:
|
||||
return kOSmacOS;
|
||||
case llvm::Triple::OSType::Linux:
|
||||
return kOSLinux;
|
||||
case llvm::Triple::OSType::Win32:
|
||||
return kOSWindows;
|
||||
case llvm::Triple::OSType::Solaris:
|
||||
return kOSSolaris;
|
||||
default:
|
||||
break;
|
||||
case llvm::Triple::OSType::MacOSX: return kOSmacOS;
|
||||
case llvm::Triple::OSType::Linux: return kOSLinux;
|
||||
case llvm::Triple::OSType::Win32: return kOSWindows;
|
||||
case llvm::Triple::OSType::Solaris: return kOSSolaris;
|
||||
default: break;
|
||||
}
|
||||
|
||||
switch (triple.getObjectFormat()) {
|
||||
case llvm::Triple::ObjectFormatType::MachO:
|
||||
return kOSmacOS;
|
||||
case llvm::Triple::ObjectFormatType::ELF:
|
||||
return kOSLinux;
|
||||
case llvm::Triple::ObjectFormatType::COFF:
|
||||
return kOSWindows;
|
||||
default:
|
||||
break;
|
||||
case llvm::Triple::ObjectFormatType::MachO: return kOSmacOS;
|
||||
case llvm::Triple::ObjectFormatType::ELF: return kOSLinux;
|
||||
case llvm::Triple::ObjectFormatType::COFF: return kOSWindows;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return kOSInvalid;
|
||||
@@ -70,16 +61,11 @@ OSName GetOSName(std::string name) {
|
||||
|
||||
std::string GetOSName(OSName name) {
|
||||
switch (name) {
|
||||
case kOSInvalid:
|
||||
return "invalid";
|
||||
case kOSmacOS:
|
||||
return "macos";
|
||||
case kOSLinux:
|
||||
return "linux";
|
||||
case kOSWindows:
|
||||
return "windows";
|
||||
case kOSSolaris:
|
||||
return "solaris";
|
||||
case kOSInvalid: return "invalid";
|
||||
case kOSmacOS: return "macos";
|
||||
case kOSLinux: return "linux";
|
||||
case kOSWindows: return "windows";
|
||||
case kOSSolaris: return "solaris";
|
||||
}
|
||||
return "invalid";
|
||||
}
|
||||
|
||||
+2
-1
@@ -31,7 +31,8 @@
|
||||
# define REMILL_ON_WINDOWS 0
|
||||
# define REMILL_ON_SOLARIS 0
|
||||
# define REMILL_OS "linux"
|
||||
# elif defined(WIN32) || defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)
|
||||
# elif defined(WIN32) || defined(_WIN32) || defined(_WIN64) || \
|
||||
defined(_MSC_VER)
|
||||
# define REMILL_ON_MACOS 0
|
||||
# define REMILL_ON_LINUX 0
|
||||
# define REMILL_ON_WINDOWS 1
|
||||
|
||||
Executable
+58
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
# Copyright 2020, Trail of Bits, Inc. All rights reserved.
|
||||
|
||||
# Get the list of changed C++ header and source files.
|
||||
STAGED_FILES=$( git diff --cached --name-only --diff-filter=ACM | grep -e '\.\(h\)\|\(cpp\)$' )
|
||||
|
||||
if [[ "${STAGED_FILES}" = "" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
PYTHON3_EXE=$( which python3 )
|
||||
if [[ "$?" == 1 ]]; then
|
||||
echo "\t\033[41mPlease install python3\033[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CLANG_FORMAT_EXE=$( which clang-format )
|
||||
if [[ "$?" == 1 ]]; then
|
||||
echo "\t\033[41mPlease install clang-format\033[0m"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
THIS_FILE_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||
NAME_OF_THIS_FILE_DIR=$( basename "${THIS_FILE_DIR}" )
|
||||
IN_SCRIPTS_DIR=0
|
||||
|
||||
# This script being executed is located in the `scripts/` directory.
|
||||
if [[ "${NAME_OF_THIS_FILE_DIR}" == "scripts" ]] ; then
|
||||
SCRIPTS_DIR="${THIS_FILE_DIR}"
|
||||
SOURCE_DIR=$( cd "$( dirname "${SCRIPTS_DIR}" )" && pwd )
|
||||
IN_SCRIPTS_DIR=1
|
||||
|
||||
# This script being executed is located in the `.git/hooks` directory.
|
||||
elif [[ "${NAME_OF_THIS_FILE_DIR}" == "hooks" ]] ; then
|
||||
GIT_DIR=$( cd "$( dirname "${SCRIPTS_DIR}" )" && pwd )
|
||||
SOURCE_DIR=$( cd "$( dirname "${GIT_DIR}" )" && pwd )
|
||||
SCRIPTS_DIR="${SOURCE_DIR}/scripts"
|
||||
|
||||
# Not sure where this script is.
|
||||
else
|
||||
echo "\t\033[41mScript '${BASH_SOURCE[0]}' is in an unexpected location\033[0m"
|
||||
echo 1
|
||||
fi
|
||||
|
||||
# Run our wrapper of `clang-format` on the files that have changed.
|
||||
${PYTHON3_EXE} "${SCRIPTS_DIR}/format-files" \
|
||||
--source_dir "${SOURCE_DIR}" \
|
||||
--format_exe "${CLANG_FORMAT_EXE}" \
|
||||
--files ${STAGED_FILES} \
|
||||
--check
|
||||
|
||||
if [[ "$?" == 0 ]] ; then
|
||||
for staged_file in ${STAGED_FILES} ; do
|
||||
git add "${staged_file}"
|
||||
done
|
||||
else
|
||||
exit 1
|
||||
fi
|
||||
Executable
+193
@@ -0,0 +1,193 @@
|
||||
#!/usr/bin/env python3
|
||||
# Copyright 2020, Trail of Bits, Inc. All rights reserved.
|
||||
|
||||
|
||||
import argparse
|
||||
import itertools
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
import sys
|
||||
import traceback
|
||||
import shutil
|
||||
|
||||
|
||||
REFLOW_COMMENT = "// !!! REFLOW-COMMENT"
|
||||
|
||||
|
||||
def find_comment_lines(path):
|
||||
new_lines = []
|
||||
old_comments = []
|
||||
needs_fixes = False
|
||||
with open(path, "r") as lines:
|
||||
num_leading_comment_lines = 0
|
||||
for line_ in lines:
|
||||
line = line_.rstrip("\n\r\t ")
|
||||
unindented_line = line.lstrip("\t ")
|
||||
|
||||
new_lines.append(line)
|
||||
|
||||
if unindented_line.startswith("//"):
|
||||
|
||||
# Make sure that every line that begins a comment block
|
||||
# is preceded by a new line or a closing brace.
|
||||
if not num_leading_comment_lines and 1 < len(new_lines):
|
||||
prev_line = new_lines[-2].strip()
|
||||
if prev_line != "" and prev_line != "}":
|
||||
new_lines[-1] = ""
|
||||
new_lines.append(line)
|
||||
needs_fixes = True
|
||||
|
||||
num_leading_comment_lines += 1
|
||||
|
||||
# The code style has it so that the comment on an `else` or `else if` statement
|
||||
# appears on the line before the `else` or `else if`.
|
||||
elif num_leading_comment_lines:
|
||||
if unindented_line.startswith("} else"):
|
||||
comment_lines = list(new_lines[-(num_leading_comment_lines + 1):-1])
|
||||
del new_lines[-(num_leading_comment_lines+1):]
|
||||
new_lines.append(REFLOW_COMMENT)
|
||||
new_lines.append(line)
|
||||
old_comments.append(comment_lines)
|
||||
needs_fixes = True
|
||||
|
||||
num_leading_comment_lines = 0
|
||||
else:
|
||||
num_leading_comment_lines = 0
|
||||
|
||||
# Force an empty newline at the end of the file.
|
||||
if len(new_lines) and new_lines[-1]:
|
||||
new_lines.append("")
|
||||
needs_fixes = True
|
||||
|
||||
return new_lines, old_comments, needs_fixes
|
||||
|
||||
|
||||
def run_clang_format_on_files(format_exe, format_file, paths):
|
||||
args = [format_exe, '-i']
|
||||
args.extend(paths)
|
||||
try:
|
||||
subprocess.check_call(args)
|
||||
except:
|
||||
return
|
||||
|
||||
|
||||
def run_clang_format_on_lines(format_exe, format_file, path, lines):
|
||||
p = subprocess.Popen(
|
||||
[format_exe,
|
||||
'--assume-filename={}'.format(path),
|
||||
'--style=file'],
|
||||
stdin=subprocess.PIPE,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
try:
|
||||
stdout_data, stderr_data = p.communicate("\n".join(lines))
|
||||
return stdout_data.split("\n"), False
|
||||
except:
|
||||
p.kill()
|
||||
stdout_data, stderr_data = p.communicate()
|
||||
return stdout_data.split("\n"), True
|
||||
|
||||
|
||||
def fixup_file(path, lines, old_comments):
|
||||
new_lines = []
|
||||
i = 0
|
||||
for line in lines:
|
||||
if line.strip() == REFLOW_COMMENT:
|
||||
num_spaces = max(0, (len(line) - len(line.lstrip())) - 2)
|
||||
new_indent = " " * num_spaces
|
||||
for old_comment_line in old_comments[i]:
|
||||
old_comment_line = old_comment_line.strip("\r\n\t ")
|
||||
new_lines.append("{}{}".format(new_indent, old_comment_line))
|
||||
i += 1
|
||||
else:
|
||||
new_lines.append(line)
|
||||
|
||||
with open(path, "w") as file:
|
||||
file.write("\n".join(new_lines))
|
||||
|
||||
|
||||
def main():
|
||||
clang_format_exe = shutil.which('clang-format')
|
||||
|
||||
arg_parser = argparse.ArgumentParser()
|
||||
|
||||
if clang_format_exe:
|
||||
arg_parser.add_argument(
|
||||
'--format_exe',
|
||||
help='Path to clang-format executable.',
|
||||
required=False,
|
||||
default=str(clang_format_exe))
|
||||
else:
|
||||
arg_parser.add_argument(
|
||||
'--format_exe',
|
||||
help='Path to clang-format executable.',
|
||||
required=True)
|
||||
|
||||
arg_parser.add_argument(
|
||||
'--source_dir',
|
||||
help='Path to root of source directory.',
|
||||
required=False,
|
||||
default=str(os.path.dirname(os.path.dirname(__file__))))
|
||||
|
||||
arg_parser.add_argument(
|
||||
'--files',
|
||||
help='Specific files to format',
|
||||
nargs='*')
|
||||
|
||||
args, _ = arg_parser.parse_known_args()
|
||||
|
||||
try:
|
||||
source_dir = os.path.abspath(args.source_dir)
|
||||
os.chdir(source_dir)
|
||||
except:
|
||||
print("'{}' passed to --source_dir is not a directory".format(args.source_dir))
|
||||
return 1
|
||||
|
||||
format_file = os.path.abspath(os.path.join(source_dir, ".clang-format"))
|
||||
if not os.path.isfile(format_file):
|
||||
print("Could not find clang-format file at '{}'".format(format_file))
|
||||
return 1
|
||||
|
||||
if not os.path.isfile(args.format_exe):
|
||||
print("'{}' passed to --format_exe does not exist".format(args.format_exe))
|
||||
return 1
|
||||
|
||||
# NOTE(pag): Go get the abs paths of the files here before we change the current
|
||||
# working directory.
|
||||
cxx_files = args.files
|
||||
if cxx_files:
|
||||
cxx_files = list(os.path.abspath(cxx_file) for cxx_file in cxx_files)
|
||||
|
||||
if not cxx_files:
|
||||
cxx_header_files = pathlib.Path(source_dir).rglob("*.h")
|
||||
cxx_source_files = pathlib.Path(source_dir).rglob("*.cpp")
|
||||
cxx_files = itertools.chain(cxx_header_files, cxx_source_files)
|
||||
|
||||
in_place_files = []
|
||||
for cxx_file_ in cxx_files:
|
||||
cxx_file = os.path.abspath(cxx_file_)
|
||||
if not (cxx_file.endswith(".h") or cxx_file.endswith(".cpp")):
|
||||
continue
|
||||
|
||||
try:
|
||||
new_lines, old_comments, needs_fixes = find_comment_lines(cxx_file)
|
||||
except:
|
||||
continue
|
||||
|
||||
if not needs_fixes:
|
||||
in_place_files.append(cxx_file)
|
||||
else:
|
||||
new_lines, has_error = run_clang_format_on_lines(
|
||||
args.format_exe, format_file, cxx_file, new_lines)
|
||||
if not has_error:
|
||||
fixup_file(cxx_file, new_lines, old_comments)
|
||||
|
||||
if in_place_files:
|
||||
run_clang_format_on_files(args.format_exe, format_file, in_place_files)
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
exit(main())
|
||||
+23
-28
@@ -14,6 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/GlobalValue.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
@@ -22,16 +31,6 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/GlobalValue.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
|
||||
#include "remill/Arch/Arch.h"
|
||||
#include "remill/Arch/Instruction.h"
|
||||
#include "remill/Arch/Name.h"
|
||||
@@ -39,7 +38,6 @@
|
||||
#include "remill/BC/Lifter.h"
|
||||
#include "remill/BC/Util.h"
|
||||
#include "remill/OS/OS.h"
|
||||
|
||||
#include "tests/AArch64/Test.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
@@ -64,11 +62,9 @@ namespace {
|
||||
// Decode a test and add it as a basic block to the module.
|
||||
//
|
||||
// TODO(pag): Eventually handle control-flow.
|
||||
static void AddFunctionToModule(llvm::Module *module,
|
||||
const remill::Arch *arch,
|
||||
static void AddFunctionToModule(llvm::Module *module, const remill::Arch *arch,
|
||||
const test::TestInfo &test) {
|
||||
DLOG(INFO)
|
||||
<< "Adding block for: " << test.test_name;
|
||||
DLOG(INFO) << "Adding block for: " << test.test_name;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << SYMBOL_PREFIX << test.test_name << "_lifted";
|
||||
@@ -109,19 +105,18 @@ static void AddFunctionToModule(llvm::Module *module,
|
||||
|
||||
remill::Instruction inst;
|
||||
CHECK(arch->DecodeInstruction(addr, inst_bytes, inst))
|
||||
<< "Can't decode test instruction " << inst.Serialize()
|
||||
<< " in " << test.test_name;
|
||||
<< "Can't decode test instruction " << inst.Serialize() << " in "
|
||||
<< test.test_name;
|
||||
|
||||
seen_insts << sep << inst.function;
|
||||
sep = ", ";
|
||||
|
||||
LOG(INFO)
|
||||
<< "Lifting " << inst.Serialize();
|
||||
LOG(INFO) << "Lifting " << inst.Serialize();
|
||||
|
||||
auto block = GetOrCreateBlock(inst.pc);
|
||||
CHECK(remill::kLiftedInstruction == lifter.LiftIntoBlock(inst, block))
|
||||
<< "Can't lift test instruction " << inst.Serialize()
|
||||
<< " in " << test.test_name;
|
||||
<< "Can't lift test instruction " << inst.Serialize() << " in "
|
||||
<< test.test_name;
|
||||
|
||||
saw_isel = saw_isel || inst.function == test.isel_name;
|
||||
addr += inst.NumBytes();
|
||||
@@ -135,8 +130,7 @@ static void AddFunctionToModule(llvm::Module *module,
|
||||
|
||||
case remill::Instruction::kCategoryDirectJump:
|
||||
case remill::Instruction::kCategoryDirectFunctionCall:
|
||||
llvm::BranchInst::Create(GetOrCreateBlock(inst.branch_taken_pc),
|
||||
block);
|
||||
llvm::BranchInst::Create(GetOrCreateBlock(inst.branch_taken_pc), block);
|
||||
break;
|
||||
|
||||
case remill::Instruction::kCategoryConditionalBranch:
|
||||
@@ -151,10 +145,10 @@ static void AddFunctionToModule(llvm::Module *module,
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(saw_isel)
|
||||
<< "Test " << test.test_name << " does not have an instruction that "
|
||||
<< "uses the semantics function " << test.isel_name << ", saw "
|
||||
<< seen_insts.str();
|
||||
CHECK(saw_isel) << "Test " << test.test_name
|
||||
<< " does not have an instruction that "
|
||||
<< "uses the semantics function " << test.isel_name
|
||||
<< ", saw " << seen_insts.str();
|
||||
|
||||
// Terminate any stragglers.
|
||||
for (auto pc_to_block : blocks) {
|
||||
@@ -185,7 +179,8 @@ extern "C" int main(int argc, char *argv[]) {
|
||||
|
||||
for (auto i = 0U;; ++i) {
|
||||
const auto &test = test::__aarch64_test_table_begin[i];
|
||||
if (&test >= &(test::__aarch64_test_table_end[0])) break;
|
||||
if (&test >= &(test::__aarch64_test_table_end[0]))
|
||||
break;
|
||||
AddFunctionToModule(module.get(), arch, test);
|
||||
}
|
||||
|
||||
|
||||
+90
-86
@@ -16,12 +16,19 @@
|
||||
|
||||
#define _XOPEN_SOURCE
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#include <cfenv>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <dlfcn.h>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
@@ -29,18 +36,9 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#include "tests/AArch64/Test.h"
|
||||
|
||||
#include "remill/Arch/Runtime/Runtime.h"
|
||||
#include "remill/Arch/AArch64/Runtime/State.h"
|
||||
#include "remill/Arch/Runtime/Runtime.h"
|
||||
#include "tests/AArch64/Test.h"
|
||||
|
||||
DECLARE_string(arch);
|
||||
DECLARE_string(os);
|
||||
@@ -62,11 +60,11 @@ static Stack gLiftedStack;
|
||||
static Stack gNativeStack;
|
||||
static Stack gSigStack;
|
||||
|
||||
static const auto gStackBase = reinterpret_cast<uintptr_t>(
|
||||
&(gLiftedStack.bytes[0]));
|
||||
static const auto gStackBase =
|
||||
reinterpret_cast<uintptr_t>(&(gLiftedStack.bytes[0]));
|
||||
|
||||
static const auto gStackLimit = reinterpret_cast<uintptr_t>(
|
||||
&(gLiftedStack._redzone2[0]));
|
||||
static const auto gStackLimit =
|
||||
reinterpret_cast<uintptr_t>(&(gLiftedStack._redzone2[0]));
|
||||
|
||||
template <typename T>
|
||||
NEVER_INLINE static T &AccessMemory(addr_t addr) {
|
||||
@@ -90,10 +88,12 @@ extern "C" {
|
||||
// initial state for the lifted testcase. The lifted test case code mutates
|
||||
// this, and we require that after running the lifted testcase, `gAArch64StateBefore`
|
||||
// matches `gAArch64StateAfter`,
|
||||
std::aligned_storage<sizeof(AArch64State), alignof(AArch64State)>::type gLiftedState;
|
||||
std::aligned_storage<sizeof(AArch64State), alignof(AArch64State)>::type
|
||||
gLiftedState;
|
||||
|
||||
// Native state after running the native test case.
|
||||
std::aligned_storage<sizeof(AArch64State), alignof(AArch64State)>::type gNativeState;
|
||||
std::aligned_storage<sizeof(AArch64State), alignof(AArch64State)>::type
|
||||
gNativeState;
|
||||
|
||||
// Address of the native test to run. The `InvokeTestCase` function saves
|
||||
// the native program state but then needs a way to figure out where to go
|
||||
@@ -115,23 +115,23 @@ uint64_t gStackSaveSlots[2] = {0, 0};
|
||||
extern void InvokeTestCase(uint64_t, uint64_t, uint64_t);
|
||||
|
||||
#define MAKE_RW_MEMORY(size) \
|
||||
NEVER_INLINE uint ## size ## _t __remill_read_memory_ ## size( \
|
||||
Memory *, addr_t addr) {\
|
||||
NEVER_INLINE uint##size##_t __remill_read_memory_##size(Memory *, \
|
||||
addr_t addr) { \
|
||||
return AccessMemory<uint##size##_t>(addr); \
|
||||
} \
|
||||
NEVER_INLINE Memory *__remill_write_memory_ ## size( \
|
||||
Memory *, addr_t addr, const uint ## size ## _t in) { \
|
||||
NEVER_INLINE Memory *__remill_write_memory_##size(Memory *, addr_t addr, \
|
||||
const uint##size##_t in) { \
|
||||
AccessMemory<uint##size##_t>(addr) = in; \
|
||||
return nullptr; \
|
||||
}
|
||||
|
||||
#define MAKE_RW_FP_MEMORY(size) \
|
||||
NEVER_INLINE float ## size ## _t __remill_read_memory_f ## size( \
|
||||
Memory *, addr_t addr) { \
|
||||
NEVER_INLINE float##size##_t __remill_read_memory_f##size(Memory *, \
|
||||
addr_t addr) { \
|
||||
return AccessMemory<float##size##_t>(addr); \
|
||||
} \
|
||||
NEVER_INLINE Memory *__remill_write_memory_f ## size(\
|
||||
Memory *, addr_t addr, float ## size ## _t in) { \
|
||||
NEVER_INLINE Memory *__remill_write_memory_f##size(Memory *, addr_t addr, \
|
||||
float##size##_t in) { \
|
||||
AccessMemory<float##size##_t>(addr) = in; \
|
||||
return nullptr; \
|
||||
}
|
||||
@@ -152,49 +152,54 @@ NEVER_INLINE Memory *__remill_write_memory_f80(Memory *, addr_t, float64_t) {
|
||||
abort();
|
||||
}
|
||||
|
||||
Memory *__remill_compare_exchange_memory_8(
|
||||
Memory *memory, addr_t addr, uint8_t &expected, uint8_t desired) {
|
||||
expected = __sync_val_compare_and_swap(
|
||||
reinterpret_cast<uint8_t *>(addr), expected, desired);
|
||||
Memory *__remill_compare_exchange_memory_8(Memory *memory, addr_t addr,
|
||||
uint8_t &expected, uint8_t desired) {
|
||||
expected = __sync_val_compare_and_swap(reinterpret_cast<uint8_t *>(addr),
|
||||
expected, desired);
|
||||
return memory;
|
||||
}
|
||||
|
||||
Memory *__remill_compare_exchange_memory_16(
|
||||
Memory *memory, addr_t addr, uint16_t &expected, uint16_t desired) {
|
||||
expected = __sync_val_compare_and_swap(
|
||||
reinterpret_cast<uint16_t *>(addr), expected, desired);
|
||||
Memory *__remill_compare_exchange_memory_16(Memory *memory, addr_t addr,
|
||||
uint16_t &expected,
|
||||
uint16_t desired) {
|
||||
expected = __sync_val_compare_and_swap(reinterpret_cast<uint16_t *>(addr),
|
||||
expected, desired);
|
||||
return memory;
|
||||
}
|
||||
|
||||
Memory *__remill_compare_exchange_memory_32(
|
||||
Memory *memory, addr_t addr, uint32_t &expected, uint32_t desired) {
|
||||
expected = __sync_val_compare_and_swap(
|
||||
reinterpret_cast<uint32_t *>(addr), expected, desired);
|
||||
Memory *__remill_compare_exchange_memory_32(Memory *memory, addr_t addr,
|
||||
uint32_t &expected,
|
||||
uint32_t desired) {
|
||||
expected = __sync_val_compare_and_swap(reinterpret_cast<uint32_t *>(addr),
|
||||
expected, desired);
|
||||
return memory;
|
||||
}
|
||||
|
||||
Memory *__remill_compare_exchange_memory_64(
|
||||
Memory *memory, addr_t addr, uint64_t &expected, uint64_t desired) {
|
||||
expected = __sync_val_compare_and_swap(
|
||||
reinterpret_cast<uint64_t *>(addr), expected, desired);
|
||||
Memory *__remill_compare_exchange_memory_64(Memory *memory, addr_t addr,
|
||||
uint64_t &expected,
|
||||
uint64_t desired) {
|
||||
expected = __sync_val_compare_and_swap(reinterpret_cast<uint64_t *>(addr),
|
||||
expected, desired);
|
||||
return memory;
|
||||
}
|
||||
|
||||
Memory *__remill_compare_exchange_memory_128(
|
||||
Memory *memory, addr_t addr, uint128_t &expected, uint128_t &desired) {
|
||||
Memory *__remill_compare_exchange_memory_128(Memory *memory, addr_t addr,
|
||||
uint128_t &expected,
|
||||
uint128_t &desired) {
|
||||
#ifdef _GXX_EXPERIMENTAL_CXX0X__
|
||||
expected = __sync_val_compare_and_swap(
|
||||
reinterpret_cast<uint128_t *>(addr), expected, desired);
|
||||
expected = __sync_val_compare_and_swap(reinterpret_cast<uint128_t *>(addr),
|
||||
expected, desired);
|
||||
#endif
|
||||
return memory;
|
||||
}
|
||||
|
||||
#define MAKE_ATOMIC_INTRINSIC(intrinsic_name, type_prefix, size) \
|
||||
Memory *__remill_ ## intrinsic_name ## _ ## size( \
|
||||
Memory *memory, addr_t addr, type_prefix ## size ## _t &value) { \
|
||||
value = __sync_ ## intrinsic_name(reinterpret_cast<type_prefix ## size ## _t *>(addr), value); \
|
||||
Memory *__remill_##intrinsic_name##_##size(Memory *memory, addr_t addr, \
|
||||
type_prefix##size##_t &value) { \
|
||||
value = __sync_##intrinsic_name( \
|
||||
reinterpret_cast<type_prefix##size##_t *>(addr), value); \
|
||||
return memory; \
|
||||
} \
|
||||
}
|
||||
|
||||
MAKE_ATOMIC_INTRINSIC(fetch_and_add, uint, 8)
|
||||
MAKE_ATOMIC_INTRINSIC(fetch_and_add, uint, 16)
|
||||
@@ -223,12 +228,24 @@ int __remill_fpu_exception_test_and_clear(int read_mask, int clear_mask) {
|
||||
return except;
|
||||
}
|
||||
|
||||
Memory *__remill_barrier_load_load(Memory *) { return nullptr; }
|
||||
Memory *__remill_barrier_load_store(Memory *) { return nullptr; }
|
||||
Memory *__remill_barrier_store_load(Memory *) { return nullptr; }
|
||||
Memory *__remill_barrier_store_store(Memory *) { return nullptr; }
|
||||
Memory *__remill_atomic_begin(Memory *) { return nullptr; }
|
||||
Memory *__remill_atomic_end(Memory *) { return nullptr; }
|
||||
Memory *__remill_barrier_load_load(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
Memory *__remill_barrier_load_store(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
Memory *__remill_barrier_store_load(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
Memory *__remill_barrier_store_store(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
Memory *__remill_atomic_begin(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
Memory *__remill_atomic_end(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void __remill_defer_inlining(void) {}
|
||||
|
||||
@@ -240,7 +257,8 @@ Memory *__remill_missing_block(AArch64State &, addr_t, Memory *memory) {
|
||||
return memory;
|
||||
}
|
||||
|
||||
Memory *__remill_sync_hyper_call(AArch64State &, Memory *, SyncHyperCall::Name) {
|
||||
Memory *__remill_sync_hyper_call(AArch64State &, Memory *,
|
||||
SyncHyperCall::Name) {
|
||||
abort();
|
||||
}
|
||||
// Read/write to I/O ports.
|
||||
@@ -337,11 +355,8 @@ inline static bool operator!=(const T &a, const T &b) {
|
||||
return !!memcmp(&a, &b, sizeof(a));
|
||||
}
|
||||
|
||||
static void RunWithFlags(const test::TestInfo *info,
|
||||
NZCV flags,
|
||||
std::string desc,
|
||||
uint64_t arg1,
|
||||
uint64_t arg2,
|
||||
static void RunWithFlags(const test::TestInfo *info, NZCV flags,
|
||||
std::string desc, uint64_t arg1, uint64_t arg2,
|
||||
uint64_t arg3) {
|
||||
|
||||
DLOG(INFO) << "Testing instruction: " << info->test_name << ": " << desc;
|
||||
@@ -391,10 +406,7 @@ static void RunWithFlags(const test::TestInfo *info,
|
||||
if (!sigsetjmp(gJmpBuf, true)) {
|
||||
std::fesetenv(FE_DFL_ENV);
|
||||
gInNativeTest = false;
|
||||
(void) lifted_func(
|
||||
*lifted_state,
|
||||
lifted_state->gpr.pc.aword,
|
||||
nullptr);
|
||||
(void) lifted_func(*lifted_state, lifted_state->gpr.pc.aword, nullptr);
|
||||
} else {
|
||||
EXPECT_TRUE(native_test_faulted);
|
||||
}
|
||||
@@ -431,19 +443,16 @@ static void RunWithFlags(const test::TestInfo *info,
|
||||
lifted_state->fpsr.flat = 0;
|
||||
|
||||
if (gLiftedState != gNativeState) {
|
||||
LOG(ERROR)
|
||||
<< "States did not match for " << desc;
|
||||
LOG(ERROR) << "States did not match for " << desc;
|
||||
EXPECT_TRUE(!"Lifted and native states did not match.");
|
||||
}
|
||||
|
||||
if (gLiftedStack != gNativeStack) {
|
||||
LOG(ERROR)
|
||||
<< "Stacks did not match for " << desc;
|
||||
LOG(ERROR) << "Stacks did not match for " << desc;
|
||||
|
||||
for (size_t i = 0; i < sizeof(gLiftedStack.bytes); ++i) {
|
||||
if (gLiftedStack.bytes[i] != gNativeStack.bytes[i]) {
|
||||
LOG(ERROR)
|
||||
<< "Lifted stack at 0x" << std::hex
|
||||
LOG(ERROR) << "Lifted stack at 0x" << std::hex
|
||||
<< reinterpret_cast<uintptr_t>(&(gLiftedStack.bytes[i]))
|
||||
<< " does not match native stack at 0x" << std::hex
|
||||
<< reinterpret_cast<uintptr_t>(&(gNativeStack.bytes[i]))
|
||||
@@ -460,8 +469,7 @@ TEST_P(InstrTest, SemanticsMatchNative) {
|
||||
CHECK(0 < info->num_args)
|
||||
<< "Test " << info->test_name << " must have at least one argument!";
|
||||
|
||||
for (auto args = info->args_begin;
|
||||
args < info->args_end;
|
||||
for (auto args = info->args_begin; args < info->args_end;
|
||||
args += info->num_args) {
|
||||
std::stringstream ss;
|
||||
ss << info->test_name;
|
||||
@@ -480,18 +488,15 @@ TEST_P(InstrTest, SemanticsMatchNative) {
|
||||
flags.flat = i << 28;
|
||||
|
||||
std::stringstream ss2;
|
||||
ss2 << desc << " and N=" << flags.n << ", Z=" << flags.z << ", C="
|
||||
<< flags.c << ", V=" << flags.v;
|
||||
ss2 << desc << " and N=" << flags.n << ", Z=" << flags.z
|
||||
<< ", C=" << flags.c << ", V=" << flags.v;
|
||||
|
||||
RunWithFlags(info, flags, ss2.str(), args[0], args[1], args[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(
|
||||
GeneralInstrTest,
|
||||
InstrTest,
|
||||
testing::ValuesIn(gTests));
|
||||
INSTANTIATE_TEST_CASE_P(GeneralInstrTest, InstrTest, testing::ValuesIn(gTests));
|
||||
|
||||
// Recover from a signal.
|
||||
static void RecoverFromError(int sig_num, siginfo_t *, void *context_) {
|
||||
@@ -502,14 +507,14 @@ static void RecoverFromError(int sig_num, siginfo_t *, void *context_) {
|
||||
auto native_state = reinterpret_cast<AArch64State *>(&gNativeState);
|
||||
auto &gpr = native_state->gpr;
|
||||
#ifdef __APPLE__
|
||||
|
||||
// const auto mcontext = context->uc_mcontext;
|
||||
// const auto &ss = mcontext->__ss;
|
||||
|
||||
(void) context;
|
||||
(void) native_state;
|
||||
(void) gpr;
|
||||
LOG(FATAL)
|
||||
<< "Implement apple signal handler.";
|
||||
LOG(FATAL) << "Implement apple signal handler.";
|
||||
#else
|
||||
|
||||
// `mcontext_t` is actually a `struct sigcontext`, defined as:
|
||||
@@ -571,9 +576,7 @@ static void RecoverFromError(int sig_num, siginfo_t *, void *context_) {
|
||||
siglongjmp(gJmpBuf, 0);
|
||||
}
|
||||
|
||||
static void ConsumeTrap(int, siginfo_t *, void *) {
|
||||
|
||||
}
|
||||
static void ConsumeTrap(int, siginfo_t *, void *) {}
|
||||
|
||||
static void HandleUnsupportedInstruction(int, siginfo_t *, void *) {
|
||||
siglongjmp(gUnsupportedInstrBuf, 0);
|
||||
@@ -621,7 +624,8 @@ int main(int argc, char **argv) {
|
||||
// Populate the tests vector.
|
||||
for (auto i = 0U;; ++i) {
|
||||
const auto &test = test::__aarch64_test_table_begin[i];
|
||||
if (&test >= &(test::__aarch64_test_table_end[0])) break;
|
||||
if (&test >= &(test::__aarch64_test_table_end[0]))
|
||||
break;
|
||||
gTests.push_back(&test);
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
@@ -21,10 +21,7 @@ struct Memory;
|
||||
|
||||
namespace test {
|
||||
|
||||
enum : size_t {
|
||||
kPageSize = 4096,
|
||||
kMaxInstrLen = 4
|
||||
};
|
||||
enum : size_t { kPageSize = 4096, kMaxInstrLen = 4 };
|
||||
|
||||
struct alignas(128) TestInfo {
|
||||
const uintptr_t test_begin;
|
||||
@@ -42,4 +39,3 @@ extern const TestInfo __aarch64_test_table_end[];
|
||||
} // extern C
|
||||
|
||||
} // namespace test
|
||||
|
||||
|
||||
+14
-17
@@ -14,6 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/GlobalValue.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
@@ -22,16 +31,6 @@
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/GlobalValue.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
|
||||
#include "remill/Arch/Arch.h"
|
||||
#include "remill/Arch/Instruction.h"
|
||||
#include "remill/Arch/Name.h"
|
||||
@@ -39,7 +38,6 @@
|
||||
#include "remill/BC/Lifter.h"
|
||||
#include "remill/BC/Util.h"
|
||||
#include "remill/OS/OS.h"
|
||||
|
||||
#include "tests/X86/Test.h"
|
||||
|
||||
#ifdef __APPLE__
|
||||
@@ -60,8 +58,8 @@ class TestTraceManager : public remill::TraceManager {
|
||||
public:
|
||||
virtual ~TestTraceManager(void) = default;
|
||||
|
||||
void SetLiftedTraceDefinition(
|
||||
uint64_t addr, llvm::Function *lifted_func) override {
|
||||
void SetLiftedTraceDefinition(uint64_t addr,
|
||||
llvm::Function *lifted_func) override {
|
||||
traces[addr] = lifted_func;
|
||||
}
|
||||
|
||||
@@ -131,8 +129,7 @@ extern "C" int main(int argc, char *argv[]) {
|
||||
|
||||
for (auto test : tests) {
|
||||
if (!trace_lifter.Lift(test->test_begin)) {
|
||||
LOG(ERROR)
|
||||
<< "Unable to lift test " << test->test_name;
|
||||
LOG(ERROR) << "Unable to lift test " << test->test_name;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -145,8 +142,8 @@ extern "C" int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
DLOG(INFO) << "Serializing bitcode to " << FLAGS_bc_out;
|
||||
auto host_arch = remill::Arch::Build(
|
||||
&context, remill::GetOSName(REMILL_OS), remill::GetArchName(REMILL_ARCH));
|
||||
auto host_arch = remill::Arch::Build(&context, remill::GetOSName(REMILL_OS),
|
||||
remill::GetArchName(REMILL_ARCH));
|
||||
host_arch->PrepareModule(module.get());
|
||||
remill::StoreModuleToFile(module.get(), FLAGS_bc_out);
|
||||
|
||||
|
||||
+246
-123
@@ -53,55 +53,72 @@ int main(void) {
|
||||
printf("pop QWORD PTR [RIP + STATE_PTR + %lu]\n", offsetof(State, rflag));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, rflag));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, aflag.cf));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n",
|
||||
offsetof(State, aflag.cf));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 2\n", offsetof(State, rflag));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, aflag.pf));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n",
|
||||
offsetof(State, aflag.pf));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 4\n", offsetof(State, rflag));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, aflag.af));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n",
|
||||
offsetof(State, aflag.af));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 6\n", offsetof(State, rflag));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, aflag.zf));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n",
|
||||
offsetof(State, aflag.zf));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 7\n", offsetof(State, rflag));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, aflag.sf));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n",
|
||||
offsetof(State, aflag.sf));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 10\n", offsetof(State, rflag));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, aflag.df));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n",
|
||||
offsetof(State, aflag.df));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 11\n", offsetof(State, rflag));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, aflag.of));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n",
|
||||
offsetof(State, aflag.of));
|
||||
|
||||
// Marshal the FPU status word flags.
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 8\n", offsetof(State, x87.fxsave.swd));
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 8\n",
|
||||
offsetof(State, x87.fxsave.swd));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, sw.c0));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 9\n", offsetof(State, x87.fxsave.swd));
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 9\n",
|
||||
offsetof(State, x87.fxsave.swd));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, sw.c1));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 10\n", offsetof(State, x87.fxsave.swd));
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 10\n",
|
||||
offsetof(State, x87.fxsave.swd));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, sw.c2));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 14\n", offsetof(State, x87.fxsave.swd));
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 14\n",
|
||||
offsetof(State, x87.fxsave.swd));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, sw.c3));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, x87.fxsave.swd));
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 0\n",
|
||||
offsetof(State, x87.fxsave.swd));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, sw.ie));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 1\n", offsetof(State, x87.fxsave.swd));
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 1\n",
|
||||
offsetof(State, x87.fxsave.swd));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, sw.de));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 2\n", offsetof(State, x87.fxsave.swd));
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 2\n",
|
||||
offsetof(State, x87.fxsave.swd));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, sw.ze));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 3\n", offsetof(State, x87.fxsave.swd));
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 3\n",
|
||||
offsetof(State, x87.fxsave.swd));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, sw.oe));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 4\n", offsetof(State, x87.fxsave.swd));
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 4\n",
|
||||
offsetof(State, x87.fxsave.swd));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, sw.ue));
|
||||
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 5\n", offsetof(State, x87.fxsave.swd));
|
||||
printf("bt QWORD PTR [RIP + STATE_PTR + %lu], 5\n",
|
||||
offsetof(State, x87.fxsave.swd));
|
||||
printf("adc BYTE PTR [RIP + STATE_PTR + %lu], 0\n", offsetof(State, sw.pe));
|
||||
|
||||
// Restore the flags.
|
||||
@@ -120,27 +137,47 @@ int main(void) {
|
||||
printf("mov WORD PTR [RIP + STATE_PTR + %lu], FS\n", offsetof(State, seg.fs));
|
||||
printf("mov WORD PTR [RIP + STATE_PTR + %lu], GS\n", offsetof(State, seg.gs));
|
||||
|
||||
printf("mov [RIP + STATE_PTR + %lu], AH\n", offsetof(State, gpr.rax.byte.high));
|
||||
printf("mov [RIP + STATE_PTR + %lu], BH\n", offsetof(State, gpr.rbx.byte.high));
|
||||
printf("mov [RIP + STATE_PTR + %lu], CH\n", offsetof(State, gpr.rcx.byte.high));
|
||||
printf("mov [RIP + STATE_PTR + %lu], DH\n", offsetof(State, gpr.rdx.byte.high));
|
||||
printf("mov [RIP + STATE_PTR + %lu], AL\n", offsetof(State, gpr.rax.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], BL\n", offsetof(State, gpr.rbx.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], CL\n", offsetof(State, gpr.rcx.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], DL\n", offsetof(State, gpr.rdx.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], AH\n",
|
||||
offsetof(State, gpr.rax.byte.high));
|
||||
printf("mov [RIP + STATE_PTR + %lu], BH\n",
|
||||
offsetof(State, gpr.rbx.byte.high));
|
||||
printf("mov [RIP + STATE_PTR + %lu], CH\n",
|
||||
offsetof(State, gpr.rcx.byte.high));
|
||||
printf("mov [RIP + STATE_PTR + %lu], DH\n",
|
||||
offsetof(State, gpr.rdx.byte.high));
|
||||
printf("mov [RIP + STATE_PTR + %lu], AL\n",
|
||||
offsetof(State, gpr.rax.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], BL\n",
|
||||
offsetof(State, gpr.rbx.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], CL\n",
|
||||
offsetof(State, gpr.rcx.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], DL\n",
|
||||
offsetof(State, gpr.rdx.byte.low));
|
||||
printf("#if 64 == ADDRESS_SIZE_BITS\n");
|
||||
printf("mov [RIP + STATE_PTR + %lu], SIL\n", offsetof(State, gpr.rsi.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], DIL\n", offsetof(State, gpr.rdi.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], SPL\n", offsetof(State, gpr.rsp.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], BPL\n", offsetof(State, gpr.rbp.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R8B\n", offsetof(State, gpr.r8.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R9B\n", offsetof(State, gpr.r9.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R10B\n", offsetof(State, gpr.r10.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R11B\n", offsetof(State, gpr.r11.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R12B\n", offsetof(State, gpr.r12.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R13B\n", offsetof(State, gpr.r13.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R14B\n", offsetof(State, gpr.r14.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R15B\n", offsetof(State, gpr.r15.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], SIL\n",
|
||||
offsetof(State, gpr.rsi.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], DIL\n",
|
||||
offsetof(State, gpr.rdi.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], SPL\n",
|
||||
offsetof(State, gpr.rsp.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], BPL\n",
|
||||
offsetof(State, gpr.rbp.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R8B\n",
|
||||
offsetof(State, gpr.r8.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R9B\n",
|
||||
offsetof(State, gpr.r9.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R10B\n",
|
||||
offsetof(State, gpr.r10.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R11B\n",
|
||||
offsetof(State, gpr.r11.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R12B\n",
|
||||
offsetof(State, gpr.r12.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R13B\n",
|
||||
offsetof(State, gpr.r13.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R14B\n",
|
||||
offsetof(State, gpr.r14.byte.low));
|
||||
printf("mov [RIP + STATE_PTR + %lu], R15B\n",
|
||||
offsetof(State, gpr.r15.byte.low));
|
||||
printf("#endif /* 64 == ADDRESS_SIZE_BITS */\n");
|
||||
printf("mov [RIP + STATE_PTR + %lu], AX\n", offsetof(State, gpr.rax.word));
|
||||
printf("mov [RIP + STATE_PTR + %lu], BX\n", offsetof(State, gpr.rbx.word));
|
||||
@@ -199,76 +236,140 @@ int main(void) {
|
||||
|
||||
printf("#if HAS_FEATURE_AVX\n");
|
||||
printf("#if HAS_FEATURE_AVX512\n");
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM0\n", offsetof(State, vec[0].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM1\n", offsetof(State, vec[1].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM2\n", offsetof(State, vec[2].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM3\n", offsetof(State, vec[3].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM4\n", offsetof(State, vec[4].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM5\n", offsetof(State, vec[5].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM6\n", offsetof(State, vec[6].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM7\n", offsetof(State, vec[7].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM8\n", offsetof(State, vec[8].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM9\n", offsetof(State, vec[9].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM10\n", offsetof(State, vec[10].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM11\n", offsetof(State, vec[11].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM12\n", offsetof(State, vec[12].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM13\n", offsetof(State, vec[13].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM14\n", offsetof(State, vec[14].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM15\n", offsetof(State, vec[15].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM16\n", offsetof(State, vec[16].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM17\n", offsetof(State, vec[17].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM18\n", offsetof(State, vec[18].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM19\n", offsetof(State, vec[19].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM20\n", offsetof(State, vec[20].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM21\n", offsetof(State, vec[21].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM22\n", offsetof(State, vec[22].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM23\n", offsetof(State, vec[23].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM24\n", offsetof(State, vec[24].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM25\n", offsetof(State, vec[25].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM26\n", offsetof(State, vec[26].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM27\n", offsetof(State, vec[27].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM28\n", offsetof(State, vec[28].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM29\n", offsetof(State, vec[29].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM30\n", offsetof(State, vec[30].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM31\n", offsetof(State, vec[31].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM0\n",
|
||||
offsetof(State, vec[0].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM1\n",
|
||||
offsetof(State, vec[1].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM2\n",
|
||||
offsetof(State, vec[2].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM3\n",
|
||||
offsetof(State, vec[3].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM4\n",
|
||||
offsetof(State, vec[4].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM5\n",
|
||||
offsetof(State, vec[5].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM6\n",
|
||||
offsetof(State, vec[6].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM7\n",
|
||||
offsetof(State, vec[7].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM8\n",
|
||||
offsetof(State, vec[8].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM9\n",
|
||||
offsetof(State, vec[9].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM10\n",
|
||||
offsetof(State, vec[10].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM11\n",
|
||||
offsetof(State, vec[11].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM12\n",
|
||||
offsetof(State, vec[12].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM13\n",
|
||||
offsetof(State, vec[13].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM14\n",
|
||||
offsetof(State, vec[14].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM15\n",
|
||||
offsetof(State, vec[15].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM16\n",
|
||||
offsetof(State, vec[16].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM17\n",
|
||||
offsetof(State, vec[17].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM18\n",
|
||||
offsetof(State, vec[18].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM19\n",
|
||||
offsetof(State, vec[19].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM20\n",
|
||||
offsetof(State, vec[20].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM21\n",
|
||||
offsetof(State, vec[21].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM22\n",
|
||||
offsetof(State, vec[22].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM23\n",
|
||||
offsetof(State, vec[23].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM24\n",
|
||||
offsetof(State, vec[24].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM25\n",
|
||||
offsetof(State, vec[25].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM26\n",
|
||||
offsetof(State, vec[26].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM27\n",
|
||||
offsetof(State, vec[27].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM28\n",
|
||||
offsetof(State, vec[28].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM29\n",
|
||||
offsetof(State, vec[29].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM30\n",
|
||||
offsetof(State, vec[30].zmm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], ZMM31\n",
|
||||
offsetof(State, vec[31].zmm));
|
||||
printf("#endif /* HAS_FEATURE_AVX512 */\n");
|
||||
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM0\n", offsetof(State, vec[0].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM1\n", offsetof(State, vec[1].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM2\n", offsetof(State, vec[2].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM3\n", offsetof(State, vec[3].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM4\n", offsetof(State, vec[4].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM5\n", offsetof(State, vec[5].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM6\n", offsetof(State, vec[6].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM7\n", offsetof(State, vec[7].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM0\n",
|
||||
offsetof(State, vec[0].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM1\n",
|
||||
offsetof(State, vec[1].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM2\n",
|
||||
offsetof(State, vec[2].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM3\n",
|
||||
offsetof(State, vec[3].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM4\n",
|
||||
offsetof(State, vec[4].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM5\n",
|
||||
offsetof(State, vec[5].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM6\n",
|
||||
offsetof(State, vec[6].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM7\n",
|
||||
offsetof(State, vec[7].ymm));
|
||||
printf("#if HAS_FEATURE_AVX || 64 == ADDRESS_SIZE_BITS\n");
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM8\n", offsetof(State, vec[8].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM9\n", offsetof(State, vec[9].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM10\n", offsetof(State, vec[10].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM11\n", offsetof(State, vec[11].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM12\n", offsetof(State, vec[12].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM13\n", offsetof(State, vec[13].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM14\n", offsetof(State, vec[14].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM15\n", offsetof(State, vec[15].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM8\n",
|
||||
offsetof(State, vec[8].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM9\n",
|
||||
offsetof(State, vec[9].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM10\n",
|
||||
offsetof(State, vec[10].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM11\n",
|
||||
offsetof(State, vec[11].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM12\n",
|
||||
offsetof(State, vec[12].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM13\n",
|
||||
offsetof(State, vec[13].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM14\n",
|
||||
offsetof(State, vec[14].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM15\n",
|
||||
offsetof(State, vec[15].ymm));
|
||||
printf("#endif /* HAS_FEATURE_AVX || 64 == ADDRESS_SIZE_BITS */\n");
|
||||
|
||||
printf("#if HAS_FEATURE_AVX512\n");
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM16\n", offsetof(State, vec[16].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM17\n", offsetof(State, vec[17].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM18\n", offsetof(State, vec[18].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM19\n", offsetof(State, vec[19].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM20\n", offsetof(State, vec[20].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM21\n", offsetof(State, vec[21].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM22\n", offsetof(State, vec[22].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM23\n", offsetof(State, vec[23].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM24\n", offsetof(State, vec[24].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM25\n", offsetof(State, vec[25].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM26\n", offsetof(State, vec[26].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM27\n", offsetof(State, vec[27].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM28\n", offsetof(State, vec[28].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM29\n", offsetof(State, vec[29].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM30\n", offsetof(State, vec[30].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM31\n", offsetof(State, vec[31].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM16\n",
|
||||
offsetof(State, vec[16].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM17\n",
|
||||
offsetof(State, vec[17].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM18\n",
|
||||
offsetof(State, vec[18].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM19\n",
|
||||
offsetof(State, vec[19].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM20\n",
|
||||
offsetof(State, vec[20].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM21\n",
|
||||
offsetof(State, vec[21].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM22\n",
|
||||
offsetof(State, vec[22].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM23\n",
|
||||
offsetof(State, vec[23].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM24\n",
|
||||
offsetof(State, vec[24].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM25\n",
|
||||
offsetof(State, vec[25].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM26\n",
|
||||
offsetof(State, vec[26].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM27\n",
|
||||
offsetof(State, vec[27].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM28\n",
|
||||
offsetof(State, vec[28].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM29\n",
|
||||
offsetof(State, vec[29].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM30\n",
|
||||
offsetof(State, vec[30].ymm));
|
||||
printf("vmovdqu [RIP + STATE_PTR + %lu], YMM31\n",
|
||||
offsetof(State, vec[31].ymm));
|
||||
printf("#endif /* HAS_FEATURE_AVX512 */\n");
|
||||
printf("#endif /* HAS_FEATURE_AVX */\n");
|
||||
|
||||
@@ -283,31 +384,53 @@ int main(void) {
|
||||
printf("#if HAS_FEATURE_AVX || 64 == ADDRESS_SIZE_BITS\n");
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM8\n", offsetof(State, vec[8].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM9\n", offsetof(State, vec[9].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM10\n", offsetof(State, vec[10].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM11\n", offsetof(State, vec[11].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM12\n", offsetof(State, vec[12].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM13\n", offsetof(State, vec[13].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM14\n", offsetof(State, vec[14].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM15\n", offsetof(State, vec[15].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM10\n",
|
||||
offsetof(State, vec[10].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM11\n",
|
||||
offsetof(State, vec[11].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM12\n",
|
||||
offsetof(State, vec[12].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM13\n",
|
||||
offsetof(State, vec[13].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM14\n",
|
||||
offsetof(State, vec[14].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM15\n",
|
||||
offsetof(State, vec[15].xmm));
|
||||
printf("#endif /* HAS_FEATURE_AVX || 64 == ADDRESS_SIZE_BITS */\n");
|
||||
|
||||
printf("#if HAS_FEATURE_AVX512\n");
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM16\n", offsetof(State, vec[16].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM17\n", offsetof(State, vec[17].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM18\n", offsetof(State, vec[18].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM19\n", offsetof(State, vec[19].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM20\n", offsetof(State, vec[20].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM21\n", offsetof(State, vec[21].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM22\n", offsetof(State, vec[22].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM23\n", offsetof(State, vec[23].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM24\n", offsetof(State, vec[24].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM25\n", offsetof(State, vec[25].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM26\n", offsetof(State, vec[26].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM27\n", offsetof(State, vec[27].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM28\n", offsetof(State, vec[28].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM29\n", offsetof(State, vec[29].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM30\n", offsetof(State, vec[30].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM31\n", offsetof(State, vec[31].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM16\n",
|
||||
offsetof(State, vec[16].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM17\n",
|
||||
offsetof(State, vec[17].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM18\n",
|
||||
offsetof(State, vec[18].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM19\n",
|
||||
offsetof(State, vec[19].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM20\n",
|
||||
offsetof(State, vec[20].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM21\n",
|
||||
offsetof(State, vec[21].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM22\n",
|
||||
offsetof(State, vec[22].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM23\n",
|
||||
offsetof(State, vec[23].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM24\n",
|
||||
offsetof(State, vec[24].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM25\n",
|
||||
offsetof(State, vec[25].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM26\n",
|
||||
offsetof(State, vec[26].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM27\n",
|
||||
offsetof(State, vec[27].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM28\n",
|
||||
offsetof(State, vec[28].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM29\n",
|
||||
offsetof(State, vec[29].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM30\n",
|
||||
offsetof(State, vec[30].xmm));
|
||||
printf("movdqu [RIP + STATE_PTR + %lu], XMM31\n",
|
||||
offsetof(State, vec[31].xmm));
|
||||
printf("#endif // HAS_FEATURE_AVX512\n");
|
||||
|
||||
return 0;
|
||||
|
||||
+120
-134
@@ -16,11 +16,18 @@
|
||||
|
||||
#define _XOPEN_SOURCE
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <dlfcn.h>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
@@ -28,19 +35,10 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <signal.h>
|
||||
#include <ucontext.h>
|
||||
|
||||
#include "tests/X86/Test.h"
|
||||
|
||||
#include "remill/Arch/Runtime/Runtime.h"
|
||||
#include "remill/Arch/Float.h"
|
||||
#include "remill/Arch/Runtime/Runtime.h"
|
||||
#include "remill/Arch/X86/Runtime/State.h"
|
||||
#include "tests/X86/Test.h"
|
||||
|
||||
DECLARE_string(arch);
|
||||
DECLARE_string(os);
|
||||
@@ -71,11 +69,11 @@ static Flags gRflagsInitial;
|
||||
|
||||
static const addr_t g64BitMask = IF_64BIT_ELSE(~0UL, 0UL);
|
||||
|
||||
static const auto gStackBase = reinterpret_cast<uintptr_t>(
|
||||
&(gLiftedStack.bytes[0]));
|
||||
static const auto gStackBase =
|
||||
reinterpret_cast<uintptr_t>(&(gLiftedStack.bytes[0]));
|
||||
|
||||
static const auto gStackLimit = reinterpret_cast<uintptr_t>(
|
||||
&(gLiftedStack._redzone2[0]));
|
||||
static const auto gStackLimit =
|
||||
reinterpret_cast<uintptr_t>(&(gLiftedStack._redzone2[0]));
|
||||
|
||||
template <typename T>
|
||||
NEVER_INLINE static T &AccessMemory(addr_t addr) {
|
||||
@@ -162,23 +160,23 @@ CR8Reg gCR8;
|
||||
extern void InvokeTestCase(uint64_t, uint64_t, uint64_t);
|
||||
|
||||
#define MAKE_RW_MEMORY(size) \
|
||||
NEVER_INLINE uint ## size ## _t __remill_read_memory_ ## size( \
|
||||
Memory *, addr_t addr) {\
|
||||
NEVER_INLINE uint##size##_t __remill_read_memory_##size(Memory *, \
|
||||
addr_t addr) { \
|
||||
return AccessMemory<uint##size##_t>(addr); \
|
||||
} \
|
||||
NEVER_INLINE Memory *__remill_write_memory_ ## size( \
|
||||
Memory *, addr_t addr, const uint ## size ## _t in) { \
|
||||
NEVER_INLINE Memory *__remill_write_memory_##size(Memory *, addr_t addr, \
|
||||
const uint##size##_t in) { \
|
||||
AccessMemory<uint##size##_t>(addr) = in; \
|
||||
return nullptr; \
|
||||
}
|
||||
|
||||
#define MAKE_RW_FP_MEMORY(size) \
|
||||
NEVER_INLINE float ## size ## _t __remill_read_memory_f ## size( \
|
||||
Memory *, addr_t addr) { \
|
||||
NEVER_INLINE float##size##_t __remill_read_memory_f##size(Memory *, \
|
||||
addr_t addr) { \
|
||||
return AccessMemory<float##size##_t>(addr); \
|
||||
} \
|
||||
NEVER_INLINE Memory *__remill_write_memory_f ## size(\
|
||||
Memory *, addr_t addr, float ## size ## _t in) { \
|
||||
NEVER_INLINE Memory *__remill_write_memory_f##size(Memory *, addr_t addr, \
|
||||
float##size##_t in) { \
|
||||
AccessMemory<float##size##_t>(addr) = in; \
|
||||
return nullptr; \
|
||||
}
|
||||
@@ -203,8 +201,8 @@ NEVER_INLINE float64_t __remill_read_memory_f128(Memory *, addr_t) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
NEVER_INLINE Memory *__remill_write_memory_f80(
|
||||
Memory *memory, addr_t addr, float64_t val) {
|
||||
NEVER_INLINE Memory *__remill_write_memory_f80(Memory *memory, addr_t addr,
|
||||
float64_t val) {
|
||||
LongDoubleStorage storage;
|
||||
auto val_long = static_cast<long double>(val);
|
||||
memcpy(&storage, &val_long, sizeof(val_long));
|
||||
@@ -218,39 +216,43 @@ NEVER_INLINE Memory *__remill_write_memory_f128(Memory *, addr_t, double) {
|
||||
}
|
||||
|
||||
|
||||
Memory *__remill_compare_exchange_memory_8(
|
||||
Memory *memory, addr_t addr, uint8_t &expected, uint8_t desired) {
|
||||
expected = __sync_val_compare_and_swap(
|
||||
reinterpret_cast<uint8_t *>(addr), expected, desired);
|
||||
Memory *__remill_compare_exchange_memory_8(Memory *memory, addr_t addr,
|
||||
uint8_t &expected, uint8_t desired) {
|
||||
expected = __sync_val_compare_and_swap(reinterpret_cast<uint8_t *>(addr),
|
||||
expected, desired);
|
||||
return memory;
|
||||
}
|
||||
|
||||
Memory *__remill_compare_exchange_memory_16(
|
||||
Memory *memory, addr_t addr, uint16_t &expected, uint16_t desired) {
|
||||
expected = __sync_val_compare_and_swap(
|
||||
reinterpret_cast<uint16_t *>(addr), expected, desired);
|
||||
Memory *__remill_compare_exchange_memory_16(Memory *memory, addr_t addr,
|
||||
uint16_t &expected,
|
||||
uint16_t desired) {
|
||||
expected = __sync_val_compare_and_swap(reinterpret_cast<uint16_t *>(addr),
|
||||
expected, desired);
|
||||
return memory;
|
||||
}
|
||||
|
||||
Memory *__remill_compare_exchange_memory_32(
|
||||
Memory *memory, addr_t addr, uint32_t &expected, uint32_t desired) {
|
||||
expected = __sync_val_compare_and_swap(
|
||||
reinterpret_cast<uint32_t *>(addr), expected, desired);
|
||||
Memory *__remill_compare_exchange_memory_32(Memory *memory, addr_t addr,
|
||||
uint32_t &expected,
|
||||
uint32_t desired) {
|
||||
expected = __sync_val_compare_and_swap(reinterpret_cast<uint32_t *>(addr),
|
||||
expected, desired);
|
||||
return memory;
|
||||
}
|
||||
|
||||
Memory *__remill_compare_exchange_memory_64(
|
||||
Memory *memory, addr_t addr, uint64_t &expected, uint64_t desired) {
|
||||
expected = __sync_val_compare_and_swap(
|
||||
reinterpret_cast<uint64_t *>(addr), expected, desired);
|
||||
Memory *__remill_compare_exchange_memory_64(Memory *memory, addr_t addr,
|
||||
uint64_t &expected,
|
||||
uint64_t desired) {
|
||||
expected = __sync_val_compare_and_swap(reinterpret_cast<uint64_t *>(addr),
|
||||
expected, desired);
|
||||
return memory;
|
||||
}
|
||||
|
||||
Memory *__remill_compare_exchange_memory_128(
|
||||
Memory *memory, addr_t addr, uint128_t &expected, uint128_t &desired) {
|
||||
Memory *__remill_compare_exchange_memory_128(Memory *memory, addr_t addr,
|
||||
uint128_t &expected,
|
||||
uint128_t &desired) {
|
||||
#if !(defined(__x86_64__) || defined(__i386__) || defined(_M_X86))
|
||||
expected = __sync_val_compare_and_swap(
|
||||
reinterpret_cast<uint128_t *>(addr), expected, desired);
|
||||
expected = __sync_val_compare_and_swap(reinterpret_cast<uint128_t *>(addr),
|
||||
expected, desired);
|
||||
#else
|
||||
bool result;
|
||||
struct alignas(16) uint128 {
|
||||
@@ -264,8 +266,8 @@ Memory *__remill_compare_exchange_memory_128(
|
||||
__asm__ __volatile__(
|
||||
"lock; cmpxchg16b %0; setz %1"
|
||||
: "=m"(*reinterpret_cast<uint128_t *>(addr)), "=q"(result)
|
||||
: "m"(*reinterpret_cast<uint128_t *>(addr)), "d" (oldval->hi), "a" (oldval->lo),
|
||||
"c" (newval->hi), "b" (newval->lo)
|
||||
: "m"(*reinterpret_cast<uint128_t *>(addr)), "d"(oldval->hi),
|
||||
"a"(oldval->lo), "c"(newval->hi), "b"(newval->lo)
|
||||
: "memory");
|
||||
|
||||
if (!result) {
|
||||
@@ -276,11 +278,12 @@ Memory *__remill_compare_exchange_memory_128(
|
||||
}
|
||||
|
||||
#define MAKE_ATOMIC_INTRINSIC(intrinsic_name, type_prefix, size) \
|
||||
Memory *__remill_ ## intrinsic_name ## _ ## size( \
|
||||
Memory *memory, addr_t addr, type_prefix ## size ## _t &value) { \
|
||||
value = __sync_ ## intrinsic_name(reinterpret_cast<type_prefix ## size ## _t *>(addr), value); \
|
||||
Memory *__remill_##intrinsic_name##_##size(Memory *memory, addr_t addr, \
|
||||
type_prefix##size##_t &value) { \
|
||||
value = __sync_##intrinsic_name( \
|
||||
reinterpret_cast<type_prefix##size##_t *>(addr), value); \
|
||||
return memory; \
|
||||
} \
|
||||
}
|
||||
|
||||
MAKE_ATOMIC_INTRINSIC(fetch_and_add, uint, 8)
|
||||
MAKE_ATOMIC_INTRINSIC(fetch_and_add, uint, 16)
|
||||
@@ -309,14 +312,30 @@ int __remill_fpu_exception_test_and_clear(int read_mask, int clear_mask) {
|
||||
return except;
|
||||
}
|
||||
|
||||
Memory *__remill_barrier_load_load(Memory *) { return nullptr; }
|
||||
Memory *__remill_barrier_load_store(Memory *) { return nullptr; }
|
||||
Memory *__remill_barrier_store_load(Memory *) { return nullptr; }
|
||||
Memory *__remill_barrier_store_store(Memory *) { return nullptr; }
|
||||
Memory *__remill_atomic_begin(Memory *) { return nullptr; }
|
||||
Memory *__remill_atomic_end(Memory *) { return nullptr; }
|
||||
Memory *__remill_delay_slot_begin(Memory *) { return nullptr; }
|
||||
Memory *__remill_delay_slot_end(Memory *) { return nullptr; }
|
||||
Memory *__remill_barrier_load_load(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
Memory *__remill_barrier_load_store(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
Memory *__remill_barrier_store_load(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
Memory *__remill_barrier_store_store(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
Memory *__remill_atomic_begin(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
Memory *__remill_atomic_end(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
Memory *__remill_delay_slot_begin(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
Memory *__remill_delay_slot_end(Memory *) {
|
||||
return nullptr;
|
||||
}
|
||||
void __remill_defer_inlining(void) {}
|
||||
|
||||
Memory *__remill_error(X86State &, addr_t, Memory *) {
|
||||
@@ -327,45 +346,31 @@ Memory *__remill_missing_block(X86State &, addr_t, Memory *memory) {
|
||||
return memory;
|
||||
}
|
||||
|
||||
Memory *__remill_sync_hyper_call(
|
||||
X86State &state, Memory *mem, SyncHyperCall::Name call) {
|
||||
Memory *__remill_sync_hyper_call(X86State &state, Memory *mem,
|
||||
SyncHyperCall::Name call) {
|
||||
switch (call) {
|
||||
case SyncHyperCall::kX86CPUID:
|
||||
asm volatile(
|
||||
"cpuid"
|
||||
: "=a"(state.gpr.rax.aword),
|
||||
"=b"(state.gpr.rbx.aword),
|
||||
"=c"(state.gpr.rcx.aword),
|
||||
"=d"(state.gpr.rdx.aword)
|
||||
: "a"(state.gpr.rax.aword),
|
||||
"b"(state.gpr.rbx.aword),
|
||||
"c"(state.gpr.rcx.aword),
|
||||
"d"(state.gpr.rdx.aword)
|
||||
);
|
||||
asm volatile("cpuid"
|
||||
: "=a"(state.gpr.rax.aword), "=b"(state.gpr.rbx.aword),
|
||||
"=c"(state.gpr.rcx.aword), "=d"(state.gpr.rdx.aword)
|
||||
: "a"(state.gpr.rax.aword), "b"(state.gpr.rbx.aword),
|
||||
"c"(state.gpr.rcx.aword), "d"(state.gpr.rdx.aword));
|
||||
break;
|
||||
|
||||
case SyncHyperCall::kX86ReadTSC:
|
||||
asm volatile(
|
||||
"rdtsc"
|
||||
: "=a"(state.gpr.rax.dword),
|
||||
"=d"(state.gpr.rdx.dword)
|
||||
);
|
||||
asm volatile("rdtsc"
|
||||
: "=a"(state.gpr.rax.dword), "=d"(state.gpr.rdx.dword));
|
||||
break;
|
||||
|
||||
case SyncHyperCall::kX86ReadTSCP:
|
||||
asm volatile(
|
||||
"rdtscp"
|
||||
: "=a"(state.gpr.rax.aword),
|
||||
"=c"(state.gpr.rcx.aword),
|
||||
asm volatile("rdtscp"
|
||||
: "=a"(state.gpr.rax.aword), "=c"(state.gpr.rcx.aword),
|
||||
"=d"(state.gpr.rdx.aword)
|
||||
: "a"(state.gpr.rax.aword),
|
||||
"c"(state.gpr.rcx.aword),
|
||||
"d"(state.gpr.rdx.aword)
|
||||
);
|
||||
: "a"(state.gpr.rax.aword), "c"(state.gpr.rcx.aword),
|
||||
"d"(state.gpr.rdx.aword));
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
default: abort();
|
||||
}
|
||||
|
||||
return mem;
|
||||
@@ -453,8 +458,7 @@ static std::map<uint64_t, LiftedFunc *> gTranslatedFuncs;
|
||||
static std::vector<const test::TestInfo *> gTests;
|
||||
|
||||
static void InitFlags(void) {
|
||||
asm(
|
||||
"pushfq;"
|
||||
asm("pushfq;"
|
||||
"pop %0;"
|
||||
:
|
||||
: "m"(gRflagsInitial));
|
||||
@@ -477,21 +481,14 @@ static bool AreFCSAndFDSDeprecated(void) {
|
||||
uint32_t edx = 0;
|
||||
|
||||
if (!FLAGS_enable_fpu_cs_ds_checking) {
|
||||
|
||||
// pretend FCS and FDS are deprecated if not checking via cmdline flag
|
||||
return true;
|
||||
}
|
||||
|
||||
asm volatile(
|
||||
"cpuid"
|
||||
: "=a"(eax),
|
||||
"=b"(ebx),
|
||||
"=c"(ecx),
|
||||
"=d"(edx)
|
||||
: "a"(eax),
|
||||
"b"(ebx),
|
||||
"c"(ecx),
|
||||
"d"(edx)
|
||||
);
|
||||
asm volatile("cpuid"
|
||||
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
|
||||
: "a"(eax), "b"(ebx), "c"(ecx), "d"(edx));
|
||||
|
||||
// Bit 13 of EBX is not zero.
|
||||
return (ebx & (1U << 13U)) != 0U;
|
||||
@@ -503,6 +500,7 @@ static bool AreFCSAndFDSDeprecated(void) {
|
||||
// type.
|
||||
static void ImportX87X86State(X86State *state) {
|
||||
auto &fpu = state->x87;
|
||||
|
||||
// Looks like MMX state.
|
||||
if (kFPUAbridgedTagValid == fpu.fxsave.ftw.r0 &&
|
||||
kFPUAbridgedTagValid == fpu.fxsave.ftw.r1 &&
|
||||
@@ -532,6 +530,7 @@ static void ImportX87X86State(X86State *state) {
|
||||
}
|
||||
|
||||
state->sw.c0 = fpu.fxsave.swd.c0;
|
||||
|
||||
// state->sw.c1 = fpu.fxsave.swd.c1; // currently we do not model C1
|
||||
state->sw.c2 = fpu.fxsave.swd.c2;
|
||||
state->sw.c3 = fpu.fxsave.swd.c3;
|
||||
@@ -560,10 +559,12 @@ static void FixGlibcMxcsrBug() {
|
||||
const uint32_t FE_ALL_EXCEPT_X86 = (FE_ALL_EXCEPT | FE_DENORMALOPERAND);
|
||||
uint32_t mxcsr = 0; // temporarily holds our MXCSR
|
||||
asm("stmxcsr %0;" : "=m"(mxcsr));
|
||||
|
||||
// assumes the rest of MXCSR was sanely set by std::fesetenv(FE_DFL_ENV);
|
||||
|
||||
// clear exceptions in MXCSR
|
||||
mxcsr &= ~FE_ALL_EXCEPT_X86;
|
||||
|
||||
// set the exception mask for future exceptions
|
||||
mxcsr |= (FE_ALL_EXCEPT_X86 << 7);
|
||||
|
||||
@@ -584,11 +585,8 @@ inline static bool operator!=(const T &a, const T &b) {
|
||||
return !!memcmp(&a, &b, sizeof(a));
|
||||
}
|
||||
|
||||
static void RunWithFlags(const test::TestInfo *info,
|
||||
Flags flags,
|
||||
std::string desc,
|
||||
uint64_t arg1,
|
||||
uint64_t arg2,
|
||||
static void RunWithFlags(const test::TestInfo *info, Flags flags,
|
||||
std::string desc, uint64_t arg1, uint64_t arg2,
|
||||
uint64_t arg3) {
|
||||
|
||||
// Can't fit a 64-bit stack address into a 32-bit register.
|
||||
@@ -652,8 +650,7 @@ static void RunWithFlags(const test::TestInfo *info,
|
||||
gInNativeTest = false;
|
||||
std::fesetenv(FE_DFL_ENV);
|
||||
FixGlibcMxcsrBug();
|
||||
(void) lifted_func(
|
||||
*lifted_state,
|
||||
(void) lifted_func(*lifted_state,
|
||||
static_cast<addr_t>(lifted_state->gpr.rip.aword),
|
||||
nullptr);
|
||||
} else {
|
||||
@@ -664,6 +661,7 @@ static void RunWithFlags(const test::TestInfo *info,
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Winvalid-offsetof"
|
||||
|
||||
// We'll compare the `ST` and `XMM` regs via their other stored forms.
|
||||
auto kill_size = sizeof(lifted_state->x87) - offsetof(FPU, fxsave.st);
|
||||
#pragma clang diagnostic pop
|
||||
@@ -672,6 +670,7 @@ static void RunWithFlags(const test::TestInfo *info,
|
||||
memset(native_state->x87.fxsave.st, 0, kill_size);
|
||||
|
||||
#if 32 == ADDRESS_SIZE_BITS
|
||||
|
||||
// If FCS and FDS are deprecated, don't compare them.
|
||||
if (AreFCSAndFDSDeprecated()) {
|
||||
lifted_state->x87.fxsave.cs = {0};
|
||||
@@ -771,9 +770,8 @@ static void RunWithFlags(const test::TestInfo *info,
|
||||
}
|
||||
|
||||
EXPECT_EQ(lifted_state->rflag, native_state->rflag)
|
||||
<< "Lifted RFLAG after test is " << std::hex
|
||||
<< lifted_state->rflag.flat << ", native is "
|
||||
<< native_state->rflag.flat << std::dec;
|
||||
<< "Lifted RFLAG after test is " << std::hex << lifted_state->rflag.flat
|
||||
<< ", native is " << native_state->rflag.flat << std::dec;
|
||||
|
||||
EXPECT_EQ(lifted_state->seg, native_state->seg)
|
||||
<< "Lifted SEG differs from native SEG";
|
||||
@@ -787,11 +785,9 @@ static void RunWithFlags(const test::TestInfo *info,
|
||||
<< native_state->x87.fxsave.swd.flat << std::dec;
|
||||
|
||||
if (gLiftedState != gNativeState) {
|
||||
EXPECT_TRUE(false)
|
||||
<< "States did not match for " << desc;
|
||||
EXPECT_TRUE(false) << "States did not match for " << desc;
|
||||
|
||||
#define DIFF(name, a) \
|
||||
EXPECT_EQ(lifted_state->a, native_state->a)
|
||||
#define DIFF(name, a) EXPECT_EQ(lifted_state->a, native_state->a)
|
||||
|
||||
DIFF(RAX, gpr.rax.aword);
|
||||
DIFF(RBX, gpr.rbx.aword);
|
||||
@@ -876,13 +872,11 @@ static void RunWithFlags(const test::TestInfo *info,
|
||||
}
|
||||
|
||||
if (gLiftedStack != gNativeStack) {
|
||||
LOG(ERROR)
|
||||
<< "Stacks did not match for " << desc;
|
||||
LOG(ERROR) << "Stacks did not match for " << desc;
|
||||
|
||||
for (size_t i = 0; i < sizeof(gLiftedStack.bytes); ++i) {
|
||||
if (gLiftedStack.bytes[i] != gNativeStack.bytes[i]) {
|
||||
LOG(ERROR)
|
||||
<< "Lifted stack at 0x" << std::hex
|
||||
LOG(ERROR) << "Lifted stack at 0x" << std::hex
|
||||
<< reinterpret_cast<uintptr_t>(&(gLiftedStack.bytes[i]))
|
||||
<< " does not match native stack at 0x" << std::hex
|
||||
<< reinterpret_cast<uintptr_t>(&(gNativeStack.bytes[i]))
|
||||
@@ -896,8 +890,7 @@ static void RunWithFlags(const test::TestInfo *info,
|
||||
|
||||
TEST_P(InstrTest, SemanticsMatchNative) {
|
||||
auto info = GetParam();
|
||||
for (auto args = info->args_begin;
|
||||
args < info->args_end;
|
||||
for (auto args = info->args_begin; args < info->args_end;
|
||||
args += info->num_args) {
|
||||
std::stringstream ss;
|
||||
ss << info->test_name << " with";
|
||||
@@ -935,12 +928,8 @@ TEST_P(InstrTest, SemanticsMatchNative) {
|
||||
|
||||
std::stringstream ss2;
|
||||
ss2 << desc << " and"
|
||||
<< " CF=" << eflags.cf
|
||||
<< " PF=" << eflags.pf
|
||||
<< " AF=" << eflags.af
|
||||
<< " ZF=" << eflags.zf
|
||||
<< " SF=" << eflags.sf
|
||||
<< " DF=" << eflags.df
|
||||
<< " CF=" << eflags.cf << " PF=" << eflags.pf << " AF=" << eflags.af
|
||||
<< " ZF=" << eflags.zf << " SF=" << eflags.sf << " DF=" << eflags.df
|
||||
<< " OF=" << eflags.of;
|
||||
|
||||
Flags flags = gRflagsInitial;
|
||||
@@ -957,9 +946,7 @@ TEST_P(InstrTest, SemanticsMatchNative) {
|
||||
}
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
GeneralInstrTest,
|
||||
InstrTest,
|
||||
INSTANTIATE_TEST_SUITE_P(GeneralInstrTest, InstrTest,
|
||||
testing::ValuesIn(gTests));
|
||||
|
||||
// Recover from a signal.
|
||||
@@ -1018,9 +1005,7 @@ static void RecoverFromError(int sig_num, siginfo_t *, void *context_) {
|
||||
siglongjmp(gJmpBuf, 0);
|
||||
}
|
||||
|
||||
static void ConsumeTrap(int, siginfo_t *, void *) {
|
||||
|
||||
}
|
||||
static void ConsumeTrap(int, siginfo_t *, void *) {}
|
||||
|
||||
static void HandleUnsupportedInstruction(int, siginfo_t *, void *) {
|
||||
siglongjmp(gUnsupportedInstrBuf, 0);
|
||||
@@ -1070,7 +1055,8 @@ int main(int argc, char **argv) {
|
||||
// Populate the tests vector.
|
||||
for (auto i = 0U;; ++i) {
|
||||
const auto &test = test::__x86_test_table_begin[i];
|
||||
if (&test >= &(test::__x86_test_table_end[0])) break;
|
||||
if (&test >= &(test::__x86_test_table_end[0]))
|
||||
break;
|
||||
gTests.push_back(&test);
|
||||
|
||||
std::stringstream ss;
|
||||
|
||||
+1
-5
@@ -21,10 +21,7 @@ struct Memory;
|
||||
|
||||
namespace test {
|
||||
|
||||
enum : size_t {
|
||||
kPageSize = 4096,
|
||||
kMaxInstrLen = 15
|
||||
};
|
||||
enum : size_t { kPageSize = 4096, kMaxInstrLen = 15 };
|
||||
|
||||
struct alignas(128) TestInfo {
|
||||
const uintptr_t test_begin;
|
||||
@@ -42,4 +39,3 @@ extern const TestInfo __x86_test_table_end[];
|
||||
} // extern C
|
||||
|
||||
} // namespace test
|
||||
|
||||
|
||||
@@ -16,6 +16,10 @@ if(EXISTS ${CMAKE_SOURCE_DIR}/tools/lift)
|
||||
add_subdirectory(lift)
|
||||
endif()
|
||||
|
||||
if(EXISTS ${CMAKE_SOURCE_DIR}/tools/circuitous)
|
||||
add_subdirectory(circuitous)
|
||||
endif()
|
||||
|
||||
# Anvill.
|
||||
if(EXISTS ${CMAKE_SOURCE_DIR}/tools/anvill)
|
||||
add_subdirectory(anvill)
|
||||
@@ -41,7 +45,7 @@ endif ()
|
||||
if (NOT WIN32)
|
||||
if (307 LESS ${REMILL_LLVM_VERSION_NUMBER})
|
||||
if (EXISTS ${CMAKE_SOURCE_DIR}/tools/vmill)
|
||||
add_subdirectory(vmill)
|
||||
#add_subdirectory(vmill)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
+60
-63
@@ -14,6 +14,27 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/GlobalValue.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
#include <llvm/Support/FileSystem.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
#include <remill/Arch/Arch.h>
|
||||
#include <remill/Arch/Instruction.h>
|
||||
#include <remill/Arch/Name.h>
|
||||
#include <remill/BC/ABI.h>
|
||||
#include <remill/BC/IntrinsicTable.h>
|
||||
#include <remill/BC/Lifter.h>
|
||||
#include <remill/BC/Optimizer.h>
|
||||
#include <remill/BC/Util.h>
|
||||
#include <remill/OS/OS.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <fstream>
|
||||
@@ -25,45 +46,26 @@
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
|
||||
#include <gflags/gflags.h>
|
||||
#include <glog/logging.h>
|
||||
|
||||
#include <llvm/IR/Function.h>
|
||||
#include <llvm/IR/GlobalValue.h>
|
||||
#include <llvm/IR/Instructions.h>
|
||||
#include <llvm/IR/IRBuilder.h>
|
||||
#include <llvm/IR/LLVMContext.h>
|
||||
#include <llvm/IR/Module.h>
|
||||
#include <llvm/IR/Type.h>
|
||||
|
||||
#include <llvm/Support/FileSystem.h>
|
||||
#include <llvm/Support/raw_ostream.h>
|
||||
|
||||
#include <remill/Arch/Arch.h>
|
||||
#include <remill/Arch/Instruction.h>
|
||||
#include <remill/Arch/Name.h>
|
||||
#include <remill/BC/ABI.h>
|
||||
#include <remill/BC/IntrinsicTable.h>
|
||||
#include <remill/BC/Lifter.h>
|
||||
#include <remill/BC/Optimizer.h>
|
||||
#include <remill/BC/Util.h>
|
||||
#include <remill/OS/OS.h>
|
||||
|
||||
DEFINE_uint64(address, 0, "Address at which we should assume the bytes are"
|
||||
DEFINE_uint64(address, 0,
|
||||
"Address at which we should assume the bytes are"
|
||||
"located in virtual memory.");
|
||||
|
||||
DEFINE_uint64(entry_address, 0, "Address of instruction that should be "
|
||||
DEFINE_uint64(entry_address, 0,
|
||||
"Address of instruction that should be "
|
||||
"considered the entrypoint of this code. "
|
||||
"Defaults to the value of --address.");
|
||||
|
||||
DEFINE_string(bytes, "", "Hex-encoded byte string to lift.");
|
||||
|
||||
DEFINE_string(ir_out, "", "Path to file where the LLVM IR should be saved.");
|
||||
DEFINE_string(bc_out, "", "Path to file where the LLVM bitcode should be "
|
||||
DEFINE_string(bc_out, "",
|
||||
"Path to file where the LLVM bitcode should be "
|
||||
"saved.");
|
||||
|
||||
DEFINE_string(slice_inputs, "", "Comma-separated list of registers to treat as inputs.");
|
||||
DEFINE_string(slice_outputs, "", "Comma-separated list of registers to treat as outputs.");
|
||||
DEFINE_string(slice_inputs, "",
|
||||
"Comma-separated list of registers to treat as inputs.");
|
||||
DEFINE_string(slice_outputs, "",
|
||||
"Comma-separated list of registers to treat as outputs.");
|
||||
|
||||
using Memory = std::map<uint64_t, uint8_t>;
|
||||
|
||||
@@ -78,9 +80,8 @@ static Memory UnhexlifyInputBytes(uint64_t addr_mask) {
|
||||
auto byte_val = strtol(nibbles, &parsed_to, 16);
|
||||
|
||||
if (parsed_to != &(nibbles[2])) {
|
||||
std::cerr
|
||||
<< "Invalid hex byte value '" << nibbles << "' specified in --bytes."
|
||||
<< std::endl;
|
||||
std::cerr << "Invalid hex byte value '" << nibbles
|
||||
<< "' specified in --bytes." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -91,14 +92,12 @@ static Memory UnhexlifyInputBytes(uint64_t addr_mask) {
|
||||
// that we don't accidentally wrap around and start filling out low
|
||||
// byte addresses.
|
||||
if (masked_addr < byte_addr) {
|
||||
std::cerr
|
||||
<< "Too many bytes specified to --bytes, would result "
|
||||
std::cerr << "Too many bytes specified to --bytes, would result "
|
||||
<< "in a 32-bit overflow.";
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
} else if (masked_addr < FLAGS_address) {
|
||||
std::cerr
|
||||
<< "Too many bytes specified to --bytes, would result "
|
||||
std::cerr << "Too many bytes specified to --bytes, would result "
|
||||
<< "in a 64-bit overflow.";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -113,14 +112,13 @@ class SimpleTraceManager : public remill::TraceManager {
|
||||
public:
|
||||
virtual ~SimpleTraceManager(void) = default;
|
||||
|
||||
explicit SimpleTraceManager(Memory &memory_)
|
||||
: memory(memory_) {}
|
||||
explicit SimpleTraceManager(Memory &memory_) : memory(memory_) {}
|
||||
|
||||
protected:
|
||||
// Called when we have lifted, i.e. defined the contents, of a new trace.
|
||||
// The derived class is expected to do something useful with this.
|
||||
void SetLiftedTraceDefinition(
|
||||
uint64_t addr, llvm::Function *lifted_func) override {
|
||||
void SetLiftedTraceDefinition(uint64_t addr,
|
||||
llvm::Function *lifted_func) override {
|
||||
traces[addr] = lifted_func;
|
||||
}
|
||||
|
||||
@@ -177,8 +175,7 @@ static void MuteStateEscape(llvm::Module *module, const char *func_name) {
|
||||
for (auto user : func->users()) {
|
||||
if (auto call_inst = llvm::dyn_cast<llvm::CallInst>(user)) {
|
||||
auto arg_op = call_inst->getArgOperand(remill::kStatePointerArgNum);
|
||||
call_inst->setArgOperand(
|
||||
remill::kStatePointerArgNum,
|
||||
call_inst->setArgOperand(remill::kStatePointerArgNum,
|
||||
llvm::UndefValue::get(arg_op->getType()));
|
||||
}
|
||||
}
|
||||
@@ -189,14 +186,14 @@ int main(int argc, char *argv[]) {
|
||||
google::InitGoogleLogging(argv[0]);
|
||||
|
||||
if (FLAGS_bytes.empty()) {
|
||||
std::cerr
|
||||
<< "Please specify a sequence of hex bytes to --bytes." << std::endl;
|
||||
std::cerr << "Please specify a sequence of hex bytes to --bytes."
|
||||
<< std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if (FLAGS_bytes.size() % 2) {
|
||||
std::cerr
|
||||
<< "Please specify an even number of nibbles to --bytes." << std::endl;
|
||||
std::cerr << "Please specify an even number of nibbles to --bytes."
|
||||
<< std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
@@ -210,8 +207,7 @@ int main(int argc, char *argv[]) {
|
||||
auto arch = remill::Arch::GetTargetArch(context);
|
||||
const uint64_t addr_mask = ~0ULL >> (64UL - arch->address_size);
|
||||
if (FLAGS_address != (FLAGS_address & addr_mask)) {
|
||||
std::cerr
|
||||
<< "Value " << std::hex << FLAGS_address
|
||||
std::cerr << "Value " << std::hex << FLAGS_address
|
||||
<< " passed to --address does not fit into 32-bits. Did mean"
|
||||
<< " to specify a 64-bit architecture to --arch?" << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
@@ -253,7 +249,8 @@ int main(int argc, char *argv[]) {
|
||||
arch->PrepareModuleDataLayout(&dest_module);
|
||||
|
||||
llvm::Function *entry_trace = nullptr;
|
||||
const auto make_slice = !FLAGS_slice_inputs.empty() || !FLAGS_slice_outputs.empty();
|
||||
const auto make_slice =
|
||||
!FLAGS_slice_inputs.empty() || !FLAGS_slice_outputs.empty();
|
||||
|
||||
// Move the lifted code into a new module. This module will be much smaller
|
||||
// because it won't be bogged down with all of the semantics definitions.
|
||||
@@ -281,10 +278,10 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
llvm::SmallVector<llvm::StringRef, 4> input_reg_names;
|
||||
llvm::SmallVector<llvm::StringRef, 4> output_reg_names;
|
||||
llvm::StringRef(FLAGS_slice_inputs).split(
|
||||
input_reg_names, ',', -1, false /* KeepEmpty */);
|
||||
llvm::StringRef(FLAGS_slice_outputs).split(
|
||||
output_reg_names, ',', -1, false /* KeepEmpty */);
|
||||
llvm::StringRef(FLAGS_slice_inputs)
|
||||
.split(input_reg_names, ',', -1, false /* KeepEmpty */);
|
||||
llvm::StringRef(FLAGS_slice_outputs)
|
||||
.split(output_reg_names, ',', -1, false /* KeepEmpty */);
|
||||
|
||||
CHECK(!(input_reg_names.empty() && output_reg_names.empty()))
|
||||
<< "Empty lists passed to both --slice_inputs and --slice_outputs";
|
||||
@@ -315,9 +312,10 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
const auto state_type = state_ptr_type->getPointerElementType();
|
||||
const auto func_type = llvm::FunctionType::get(mem_ptr_type, arg_types, false);
|
||||
const auto func = llvm::Function::Create(func_type, llvm::GlobalValue::ExternalLinkage,
|
||||
"slice", &dest_module);
|
||||
const auto func_type =
|
||||
llvm::FunctionType::get(mem_ptr_type, arg_types, false);
|
||||
const auto func = llvm::Function::Create(
|
||||
func_type, llvm::GlobalValue::ExternalLinkage, "slice", &dest_module);
|
||||
|
||||
// Store all of the function arguments (corresponding with specific registers)
|
||||
// into the stack-allocated `State` structure.
|
||||
@@ -326,8 +324,8 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
const auto state_ptr = ir.CreateAlloca(state_type);
|
||||
|
||||
const remill::Register *pc_reg = arch->RegisterByName(
|
||||
arch->ProgramCounterRegisterName());
|
||||
const remill::Register *pc_reg =
|
||||
arch->RegisterByName(arch->ProgramCounterRegisterName());
|
||||
|
||||
CHECK(pc_reg != nullptr)
|
||||
<< "Could not find the register in the state structure "
|
||||
@@ -335,7 +333,8 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
// Store the program counter into the state.
|
||||
const auto pc_reg_ptr = pc_reg->AddressOf(state_ptr, entry);
|
||||
const auto trace_pc = llvm::ConstantInt::get(pc_reg->type, FLAGS_entry_address, false);
|
||||
const auto trace_pc =
|
||||
llvm::ConstantInt::get(pc_reg->type, FLAGS_entry_address, false);
|
||||
ir.SetInsertPoint(entry);
|
||||
ir.CreateStore(trace_pc, pc_reg_ptr);
|
||||
|
||||
@@ -400,15 +399,13 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
if (!FLAGS_ir_out.empty()) {
|
||||
if (!remill::StoreModuleIRToFile(&dest_module, FLAGS_ir_out, true)) {
|
||||
LOG(ERROR)
|
||||
<< "Could not save LLVM IR to " << FLAGS_ir_out;
|
||||
LOG(ERROR) << "Could not save LLVM IR to " << FLAGS_ir_out;
|
||||
ret = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
if (!FLAGS_bc_out.empty()) {
|
||||
if (!remill::StoreModuleToFile(&dest_module, FLAGS_bc_out, true)) {
|
||||
LOG(ERROR)
|
||||
<< "Could not save LLVM bitcode to " << FLAGS_bc_out;
|
||||
LOG(ERROR) << "Could not save LLVM bitcode to " << FLAGS_bc_out;
|
||||
ret = EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user