Merge pull request #20 from emawind84/questzdoom

Merge to rebase1
This commit is contained in:
Simon 2021-09-29 22:31:32 +01:00 committed by GitHub
commit 4abfa88af8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3368 changed files with 167 additions and 1037172 deletions

4
.gitmodules vendored Normal file
View File

@ -0,0 +1,4 @@
[submodule "gzdoom"]
path = Projects/Android/jni/gzdoom-g3.3mgw_mobile
url = https://github.com/emawind84/gzdoom.git
branch = questzdoom

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.drbeef.questzdoom"
android:versionCode="28"
android:versionName="1.2.3" android:installLocation="auto" >
android:versionCode="29"
android:versionName="1.3.0" android:installLocation="auto" >
<!-- Tell the system this app requires OpenGL ES 3.1. -->
<uses-feature android:glEsVersion="0x00030001" android:required="true"/>
@ -19,6 +19,7 @@
<application android:allowBackup="false" android:icon="@drawable/ic_qquest" android:label="@string/qzdoom">
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
<meta-data android:name="com.oculus.supportedDevices" android:value="quest|quest2"/>
<meta-data android:name="com.oculus.ossplash" android:value="true"/>
<!-- The activity is the built-in NativeActivity framework class. -->
<!-- launchMode is set to singleTask because there should never be multiple copies of the app running. -->
<!-- Theme.Black.NoTitleBar.Fullscreen gives solid black instead of a (bad stereoscopic) gradient on app transition. -->

View File

@ -701,7 +701,7 @@ void ovrRenderer_Create( int width, int height, ovrRenderer * renderer, const ov
renderer->NumBuffers = VRAPI_FRAME_LAYER_EYE_MAX;
//Now using a symmetrical render target, based on the horizontal FOV
QzDoom_GetFOV();
//QzDoom_GetFOV();
// Create the render Textures.
for ( int eye = 0; eye < VRAPI_FRAME_LAYER_EYE_MAX; eye++ )
@ -1335,6 +1335,29 @@ int QzDoom_GetRefresh()
return vrapi_GetSystemPropertyInt(&gAppState.Java, VRAPI_SYS_PROP_DISPLAY_REFRESH_RATE);
}
int QzDoom_SetRefreshRate(int refreshRate)
{
return vrapi_SetDisplayRefreshRate(gAppState.Ovr, (float)refreshRate);
}
bool QzDoom_IsRefreshSupported(int refreshRate)
{
int size = vrapi_GetSystemPropertyInt(&gAppState.Java, VRAPI_SYS_PROP_NUM_SUPPORTED_DISPLAY_REFRESH_RATES);
float supported_rates[size];
int elements = vrapi_GetSystemPropertyFloatArray(&gAppState.Java,
VRAPI_SYS_PROP_SUPPORTED_DISPLAY_REFRESH_RATES,
supported_rates, size);
for (int i = 0; i < size; i++)
{
if (refreshRate == (int)supported_rates[i])
{
return true;
}
}
ALOGV("Refresh rate not supported: %dHz", refreshRate);
return false;
}
float QzDoom_GetFOV()
{
vrFOV = vrapi_GetSystemPropertyInt(&gAppState.Java, VRAPI_SYS_PROP_SUGGESTED_EYE_FOV_DEGREES_Y);
@ -1499,6 +1522,10 @@ void * AppThreadFunction(void * parm ) {
return NULL;
}
if (QzDoom_IsRefreshSupported(DISPLAY_REFRESH)) {
QzDoom_SetRefreshRate(DISPLAY_REFRESH);
}
// Create the scene if not yet created.
ovrScene_Create( m_width, m_height, &gAppState.Scene, &java );
@ -1530,11 +1557,6 @@ void QzDoom_FrameSetup()
{
//Use floor based tracking space
vrapi_SetTrackingSpace(gAppState.Ovr, VRAPI_TRACKING_SPACE_LOCAL_FLOOR);
//Set the screen refresh - repeat this every frame so VrApi doesn't try changing it on us
if (DISPLAY_REFRESH != -1) {
vrapi_SetDisplayRefreshRate(gAppState.Ovr, DISPLAY_REFRESH);
}
}
void QzDoom_processHaptics() {//Handle haptics
@ -1866,7 +1888,7 @@ JNIEXPORT jlong JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_onCreate( JNIEnv
gpu = arg_int0("g", "gpu", "<int>", "GPU perf index 1-4 (default: 3)"),
msaa = arg_int0("m", "msaa", "<int>", "MSAA 1-4 (default: 1)"),
ffr = arg_int0("f", "ffr", "<int>", "FFR 0-4 (default: 0)"),
refresh = arg_int0("r", "refresh", "<int>", "Display Refresh 60 or 72 (default: 72)"),
refresh = arg_int0("r", "refresh", "<int>", "Display Refresh 60, 72 or 90 (default: 72)"),
end = arg_end(20)
};
@ -1918,7 +1940,7 @@ JNIEXPORT jlong JNICALL Java_com_drbeef_questzdoom_GLES3JNILib_onCreate( JNIEnv
FFR = ffr->ival[0];
}
if (refresh->count > 0 && (refresh->ival[0] == 60 || refresh->ival[0] == 72))
if (refresh->count > 0 && (refresh->ival[0] == 60 || refresh->ival[0] == 72 || refresh->ival[0] == 90 || refresh->ival[0] == 120))
{
DISPLAY_REFRESH = refresh->ival[0];
}

View File

@ -92,6 +92,7 @@ void QzDoom_setUseScreenLayer(bool use);
void QzDoom_processHaptics();
void QzDoom_getHMDOrientation(ovrTracking2 *tracking);
void QzDoom_getTrackedRemotesOrientation(int vr_control_scheme);
int QzDoom_SetRefreshRate(int refreshRate);
void QzDoom_HapticEvent(const char* event, int position, int intensity, float angle, float yHeight );
void QzDoom_HapticEnable();

View File

@ -33,21 +33,6 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
handleTrackedControllerButton(&leftTrackedRemoteState_new, &leftTrackedRemoteState_old, ovrButton_Enter, KEY_ESCAPE);
handleTrackedControllerButton(&rightTrackedRemoteState_new, &rightTrackedRemoteState_old, ovrButton_Enter, KEY_ESCAPE); // For users who have switched the buttons
if (getGameState() != 0 || getMenuState() == 1) // If getMenuState returns 2, then we are waiting for a key mapping input, so send normal keymappings, don't send these
{
Joy_GenerateButtonEvents((pOffTrackedRemoteOld->Joystick.x > 0.7f ? 1 : 0), (pOffTrackedRemoteNew->Joystick.x > 0.7f ? 1 : 0), 1, KEY_PAD_DPAD_RIGHT);
Joy_GenerateButtonEvents((pDominantTrackedRemoteOld->Joystick.x > 0.7f ? 1 : 0), (pDominantTrackedRemoteNew->Joystick.x > 0.7f ? 1 : 0), 1, KEY_PAD_DPAD_RIGHT);
Joy_GenerateButtonEvents((pOffTrackedRemoteOld->Joystick.x < -0.7f ? 1 : 0), (pOffTrackedRemoteNew->Joystick.x < -0.7f ? 1 : 0), 1, KEY_PAD_DPAD_LEFT);
Joy_GenerateButtonEvents((pDominantTrackedRemoteOld->Joystick.x < -0.7f ? 1 : 0), (pDominantTrackedRemoteNew->Joystick.x < -0.7f ? 1 : 0), 1, KEY_PAD_DPAD_LEFT);
Joy_GenerateButtonEvents((pOffTrackedRemoteOld->Joystick.y < -0.7f ? 1 : 0), (pOffTrackedRemoteNew->Joystick.y < -0.7f ? 1 : 0), 1, KEY_PAD_DPAD_DOWN);
Joy_GenerateButtonEvents((pDominantTrackedRemoteOld->Joystick.y < -0.7f ? 1 : 0), (pDominantTrackedRemoteNew->Joystick.y < -0.7f ? 1 : 0), 1, KEY_PAD_DPAD_DOWN);
Joy_GenerateButtonEvents((pOffTrackedRemoteOld->Joystick.y > 0.7f ? 1 : 0), (pOffTrackedRemoteNew->Joystick.y > 0.7f ? 1 : 0), 1, KEY_PAD_DPAD_UP);
Joy_GenerateButtonEvents((pDominantTrackedRemoteOld->Joystick.y > 0.7f ? 1 : 0), (pDominantTrackedRemoteNew->Joystick.y > 0.7f ? 1 : 0), 1, KEY_PAD_DPAD_UP);
}
//Dominant Grip works like a shift key
bool dominantGripPushedOld = vr_secondarybuttonmappings ?
(pDominantTrackedRemoteOld->Buttons & ovrButton_GripTrigger) != 0 : false;
@ -105,6 +90,18 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
secondaryButton2 = offButton2;
}
Joy_GenerateButtonEvents((pSecondaryTrackedRemoteOld->Joystick.x > 0.7f ? 1 : 0), (pSecondaryTrackedRemoteNew->Joystick.x > 0.7f ? 1 : 0), 1, KEY_JOYAXIS1PLUS);
Joy_GenerateButtonEvents((pSecondaryTrackedRemoteOld->Joystick.x < -0.7f ? 1 : 0), (pSecondaryTrackedRemoteNew->Joystick.x < -0.7f ? 1 : 0), 1, KEY_JOYAXIS1MINUS);
Joy_GenerateButtonEvents((pPrimaryTrackedRemoteOld->Joystick.x > 0.7f ? 1 : 0), (pPrimaryTrackedRemoteNew->Joystick.x > 0.7f ? 1 : 0), 1, KEY_JOYAXIS3PLUS);
Joy_GenerateButtonEvents((pPrimaryTrackedRemoteOld->Joystick.x < -0.7f ? 1 : 0), (pPrimaryTrackedRemoteNew->Joystick.x < -0.7f ? 1 : 0), 1, KEY_JOYAXIS3MINUS);
Joy_GenerateButtonEvents((pSecondaryTrackedRemoteOld->Joystick.y < -0.7f ? 1 : 0), (pSecondaryTrackedRemoteNew->Joystick.y < -0.7f ? 1 : 0), 1, KEY_JOYAXIS2MINUS);
Joy_GenerateButtonEvents((pSecondaryTrackedRemoteOld->Joystick.y > 0.7f ? 1 : 0), (pSecondaryTrackedRemoteNew->Joystick.y > 0.7f ? 1 : 0), 1, KEY_JOYAXIS2PLUS);
Joy_GenerateButtonEvents((pPrimaryTrackedRemoteOld->Joystick.y < -0.7f ? 1 : 0), (pPrimaryTrackedRemoteNew->Joystick.y < -0.7f ? 1 : 0), 1, KEY_JOYAXIS4MINUS);
Joy_GenerateButtonEvents((pPrimaryTrackedRemoteOld->Joystick.y > 0.7f ? 1 : 0), (pPrimaryTrackedRemoteNew->Joystick.y > 0.7f ? 1 : 0), 1, KEY_JOYAXIS4PLUS);
//In cinema mode, right-stick controls mouse
const float mouseSpeed = 3.0f;
if (cinemamode)
@ -148,15 +145,11 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
weaponoffset[1] = pDominantTracking->HeadPose.Pose.Position.y - hmdPosition[1];
weaponoffset[2] = pDominantTracking->HeadPose.Pose.Position.z - hmdPosition[2];
{
vec2_t v;
float yawRotation = cinemamode ? getViewpointYaw() - hmdorientation[YAW] :
doomYaw - hmdorientation[YAW];
rotateAboutOrigin(weaponoffset[0], weaponoffset[2],
-yawRotation, v);
weaponoffset[0] = v[1];
weaponoffset[2] = v[0];
}
vec2_t v;
float yawRotation = getViewpointYaw() - hmdorientation[YAW];
rotateAboutOrigin(weaponoffset[0], weaponoffset[2], -yawRotation, v);
weaponoffset[0] = v[1];
weaponoffset[2] = v[0];
//Set gun angles
const ovrQuatf quatRemote = pDominantTracking->HeadPose.Pose.Orientation;
@ -190,15 +183,15 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
offhandoffset[2] = pOffTracking->HeadPose.Pose.Position.z - hmdPosition[2];
vec2_t v;
rotateAboutOrigin(offhandoffset[0], offhandoffset[2], -(doomYaw - hmdorientation[YAW]),
v);
float yawRotation = getViewpointYaw() - hmdorientation[YAW];
rotateAboutOrigin(offhandoffset[0], offhandoffset[2], -yawRotation, v);
offhandoffset[0] = v[1];
offhandoffset[2] = v[0];
vec3_t rotation = {0};
QuatToYawPitchRoll(pOffTracking->HeadPose.Pose.Orientation, rotation, offhandangles);
if (vr_moveuseoffhand != 0) {
if (vr_moveuseoffhand) {
controllerYawHeading = offhandangles[YAW] - hmdorientation[YAW];
} else {
controllerYawHeading = 0.0f;
@ -318,18 +311,18 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
between(-1.0f, pPrimaryTrackedRemoteNew->Joystick.y, -0.8f))) {
if (itemSwitched == 0) {
if (between(0.8f, pPrimaryTrackedRemoteNew->Joystick.y, 1.0f)) {
Joy_GenerateButtonEvents(0, 1, 1, KEY_MWHEELDOWN);
Joy_GenerateButtonEvents(0, 1, 1, KEY_MWHEELUP);
itemSwitched = 1;
} else {
Joy_GenerateButtonEvents(0, 1, 1, KEY_MWHEELUP);
Joy_GenerateButtonEvents(0, 1, 1, KEY_MWHEELDOWN);
itemSwitched = 2;
}
}
} else {
if (itemSwitched == 1) {
Joy_GenerateButtonEvents(1, 0, 1, KEY_MWHEELDOWN);
} else if (itemSwitched == 2) {
Joy_GenerateButtonEvents(1, 0, 1, KEY_MWHEELUP);
} else if (itemSwitched == 2) {
Joy_GenerateButtonEvents(1, 0, 1, KEY_MWHEELDOWN);
}
itemSwitched = 0;
}
@ -385,7 +378,10 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
((pDominantTrackedRemoteNew->Buttons & ovrButton_Joystick) != 0) && !dominantGripPushedNew ? 1 : 0,
1, KEY_ENTER);
//No Default Binding
Joy_GenerateButtonEvents(((pDominantTrackedRemoteOld->Touches & ovrTouch_ThumbRest) != 0) && !dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Touches & ovrTouch_ThumbRest) != 0) && !dominantGripPushedNew ? 1 : 0,
1, KEY_JOY5);
if (vr_secondarybuttonmappings) {
//Dominant Hand - Secondary keys (grip pushed)
@ -418,6 +414,13 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
((pDominantTrackedRemoteNew->Buttons & ovrButton_Joystick) != 0) &&
dominantGripPushedNew ? 1 : 0,
1, KEY_TAB);
//No Default Binding
Joy_GenerateButtonEvents(
((pDominantTrackedRemoteOld->Touches & ovrTouch_ThumbRest) != 0) && dominantGripPushedOld ? 1 : 0,
((pDominantTrackedRemoteNew->Touches & ovrTouch_ThumbRest) != 0) && dominantGripPushedNew ? 1 : 0,
1, KEY_JOY6);
} else {
//Use grip as an extra button
//Alt-Fire
@ -451,6 +454,11 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
((pOffTrackedRemoteNew->Buttons & ovrButton_Joystick) != 0) && !dominantGripPushedNew ? 1 : 0,
1, KEY_SPACE);
//No Default Binding
Joy_GenerateButtonEvents(((pOffTrackedRemoteOld->Touches & ovrTouch_ThumbRest) != 0) && !dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Touches & ovrTouch_ThumbRest) != 0) && !dominantGripPushedNew ? 1 : 0,
1, KEY_JOY7);
if (!vr_twohandedweapons)
{
Joy_GenerateButtonEvents(
@ -496,6 +504,12 @@ void HandleInput_Default( int control_scheme, ovrInputStateGamepad *pFootTrackin
dominantGripPushedNew ? 1 : 0,
1, KEY_HOME);
//No Default Binding
Joy_GenerateButtonEvents(
((pOffTrackedRemoteOld->Touches & ovrTouch_ThumbRest) != 0) && dominantGripPushedOld ? 1 : 0,
((pOffTrackedRemoteNew->Touches & ovrTouch_ThumbRest) != 0) && dominantGripPushedNew ? 1 : 0,
1, KEY_JOY8);
if (!vr_twohandedweapons)
{
Joy_GenerateButtonEvents(

View File

@ -195,7 +195,88 @@
#define KEY_JOY4AXIS8PLUS 0x222
#define KEY_JOY4AXIS8MINUS 0x223
#define NUM_KEYS 0x224
#define KEY_PAD2_LTHUMB_RIGHT 0x224
#define KEY_PAD2_LTHUMB_LEFT 0x225
#define KEY_PAD2_LTHUMB_DOWN 0x226
#define KEY_PAD2_LTHUMB_UP 0x227
#define KEY_PAD2_RTHUMB_RIGHT 0x228
#define KEY_PAD2_RTHUMB_LEFT 0x229
#define KEY_PAD2_RTHUMB_DOWN 0x22A
#define KEY_PAD2_RTHUMB_UP 0x22B
#define KEY_PAD2_DPAD_UP 0x22C
#define KEY_PAD2_DPAD_DOWN 0x22D
#define KEY_PAD2_DPAD_LEFT 0x22E
#define KEY_PAD2_DPAD_RIGHT 0x22F
#define KEY_PAD2_START 0x230
#define KEY_PAD2_BACK 0x231
#define KEY_PAD2_LTHUMB 0x232
#define KEY_PAD2_RTHUMB 0x233
#define KEY_PAD2_LSHOULDER 0x234
#define KEY_PAD2_RSHOULDER 0x235
#define KEY_PAD2_LTRIGGER 0x236
#define KEY_PAD2_RTRIGGER 0x237
#define KEY_PAD2_A 0x238
#define KEY_PAD2_B 0x239
#define KEY_PAD2_X 0x23A
#define KEY_PAD2_Y 0x23B
#define KEY_PAD3_LTHUMB_RIGHT 0x23C
#define KEY_PAD3_LTHUMB_LEFT 0x23D
#define KEY_PAD3_LTHUMB_DOWN 0x23E
#define KEY_PAD3_LTHUMB_UP 0x23F
#define KEY_PAD3_RTHUMB_RIGHT 0x240
#define KEY_PAD3_RTHUMB_LEFT 0x241
#define KEY_PAD3_RTHUMB_DOWN 0x242
#define KEY_PAD3_RTHUMB_UP 0x243
#define KEY_PAD3_DPAD_UP 0x244
#define KEY_PAD3_DPAD_DOWN 0x245
#define KEY_PAD3_DPAD_LEFT 0x246
#define KEY_PAD3_DPAD_RIGHT 0x247
#define KEY_PAD3_START 0x248
#define KEY_PAD3_BACK 0x249
#define KEY_PAD3_LTHUMB 0x24A
#define KEY_PAD3_RTHUMB 0x24B
#define KEY_PAD3_LSHOULDER 0x24C
#define KEY_PAD3_RSHOULDER 0x24D
#define KEY_PAD3_LTRIGGER 0x24E
#define KEY_PAD3_RTRIGGER 0x24F
#define KEY_PAD3_A 0x250
#define KEY_PAD3_B 0x251
#define KEY_PAD3_X 0x252
#define KEY_PAD3_Y 0x253
#define KEY_PAD4_LTHUMB_RIGHT 0x254
#define KEY_PAD4_LTHUMB_LEFT 0x255
#define KEY_PAD4_LTHUMB_DOWN 0x256
#define KEY_PAD4_LTHUMB_UP 0x257
#define KEY_PAD4_RTHUMB_RIGHT 0x258
#define KEY_PAD4_RTHUMB_LEFT 0x259
#define KEY_PAD4_RTHUMB_DOWN 0x25A
#define KEY_PAD4_RTHUMB_UP 0x25B
#define KEY_PAD4_DPAD_UP 0x25C
#define KEY_PAD4_DPAD_DOWN 0x25D
#define KEY_PAD4_DPAD_LEFT 0x25E
#define KEY_PAD4_DPAD_RIGHT 0x25F
#define KEY_PAD4_START 0x260
#define KEY_PAD4_BACK 0x261
#define KEY_PAD4_LTHUMB 0x262
#define KEY_PAD4_RTHUMB 0x263
#define KEY_PAD4_LSHOULDER 0x264
#define KEY_PAD4_RSHOULDER 0x265
#define KEY_PAD4_LTRIGGER 0x266
#define KEY_PAD4_RTRIGGER 0x267
#define KEY_PAD4_A 0x268
#define KEY_PAD4_B 0x269
#define KEY_PAD4_X 0x26A
#define KEY_PAD4_Y 0x26B
#define NUM_KEYS 0x26C
#endif //QZDOOM_DOOMKEYS_H

@ -0,0 +1 @@
Subproject commit 9155ab78b52e490213659a570fccce3c4a65f224

View File

@ -1,54 +0,0 @@
version: "{build}"
branches:
except:
- /^travis.*$/
clone_depth: 10
environment:
matrix:
- GENERATOR: "Visual Studio 14 2015"
ARCH: Win32
CONFIGURATION: Release
TOOLSET: v140_xp
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2015"
- GENERATOR: "Visual Studio 15 2017"
ARCH: x64
CONFIGURATION: Release
TOOLSET: v141
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2017"
- GENERATOR: "Visual Studio 16 2019"
ARCH: Win32
CONFIGURATION: Release
TOOLSET: v142
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2019"
- GENERATOR: "Visual Studio 16 2019"
ARCH: x64
CONFIGURATION: Release
TOOLSET: v142
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2019"
- GENERATOR: "Visual Studio 16 2019"
ARCH: x64
CONFIGURATION: Debug
TOOLSET: v142
APPVEYOR_BUILD_WORKER_IMAGE: "Visual Studio 2019"
build_script:
- md build
- cd build
- cmake -G "%GENERATOR%" -A %ARCH% -T "%TOOLSET%" -DPK3_QUIET_ZIPDIR=YES ..
- cmake --build . --config "%CONFIGURATION%" -- -maxcpucount -verbosity:minimal
after_build:
- set OUTPUT_DIR=%APPVEYOR_BUILD_FOLDER%\build\%CONFIGURATION%\
- 7z a ..\lzdoom.zip "%OUTPUT_DIR%lzdoom.exe" "%OUTPUT_DIR%*.pk3"
artifacts:
- path: lzdoom.zip
notifications:
- provider: Email
on_build_success: false
on_build_failure: false
on_build_status_changed: false

View File

@ -1,27 +0,0 @@
* text=auto
*.h text
*.c text
*.cc text
*.cpp text
*.mm text
*.lemon text
*.y text
*.re text
*.i text
*.asm text
*.S text
*.vcproj text eol=crlf
*.sln text eol=crlf
*.bat text eol=crlf
*.rc text eol=crlf
*.txt text
language.* text
*.png binary
*.imgz binary
*.lmp binary
*.flac binary
*.dat binary

View File

@ -1,57 +0,0 @@
/Debug
*.ncb
*.suo
*.pdb
*.ilk
*.aps
/fmodapi*/
/Release
/wadsrc_wad
*.user
/build
/debug
/release
*/debug
*/release
/release_gcc
/dumb/vc6/dumb_static/release
/dumb/vc6/dumb_static/debug
/dumb/vc6/dumb_static/x64
/DOOMSTATS.TXT
/src/gitinfo.h
/src/sc_man_scanner.h
/src/xlat/xlat_parser.c
/src/xlat/xlat_parser.h
/src/xlat/xlat_parser.out
/src/zscript/zcc-parse.c
/src/zscript/zcc-parse.h
/src/zscript/zcc-parse.out
/tools/*/debug
/tools/*/release
/tools/*/*.exe
/tools/lemon/build
/tools/re2c/build
/tools/updaterevision/x64/
/tools/zipdir/x64
/wadsrc/*.pk3
/build_vc2013
/bzip2/x64/
/disasm.txt
/game-music-emu/x64/
/gdtoa/x64/
/jpeg-6b/x64/
/lzma/x64/
/zlib/x64/
/build_vc2013_64bit
/build_vc2015
/build_vc2015-32
/build_vc2015-64
/build_vc2017-64
/build
/llvm
/src/r_drawersasm.obj
/src/r_drawersasm.o
.vs
/src/gl/unused
/mapfiles_release/*.map
.DS_Store

View File

@ -1,152 +0,0 @@
language: cpp
dist: xenial
branches:
except:
- /^appveyor.*$/
git:
depth: 10
matrix:
include:
- os: osx
osx_image: xcode8
env:
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Debug -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9"
- os: osx
osx_image: xcode10.3
env:
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_OSX_DEPLOYMENT_TARGET=10.9"
- os: windows
env:
- CMAKE_OPTIONS="-A Win32"
- os: windows
env:
- CMAKE_OPTIONS="-A x64"
- os: linux
compiler: gcc
env:
- GCC_VERSION=4.9
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-Wno-maybe-uninitialized"
addons:
apt:
packages:
- g++-4.9
- libsdl2-dev
- libgtk2.0-dev
- os: linux
compiler: gcc
env:
- GCC_VERSION=5
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS=-Wno-maybe-uninitialized"
addons:
apt:
packages:
- g++-5
- libsdl2-dev
- libgtk-3-dev
- os: linux
compiler: gcc
env:
- GCC_VERSION=6
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_CXX_FLAGS=-Wno-maybe-uninitialized"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-6
- libsdl2-dev
- libgtk2.0-dev
- os: linux
compiler: gcc
env:
- GCC_VERSION=7
- CMAKE_OPTIONS="-DCMAKE_CXX_FLAGS=-Wno-implicit-fallthrough"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-7
- libsdl2-dev
- libgtk-3-dev
- os: linux
compiler: gcc
env:
- GCC_VERSION=8
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=MinSizeRel -DCMAKE_CXX_FLAGS=-Wno-implicit-fallthrough"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
- libsdl2-dev
- libgtk-3-dev
- os: linux
compiler: gcc
env:
- GCC_VERSION=9
- CMAKE_OPTIONS="-DCMAKE_CXX_FLAGS=-Wno-implicit-fallthrough"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-9
- libsdl2-dev
- os: linux
compiler: clang
env:
- CLANG_VERSION=8
- CMAKE_OPTIONS="-DCMAKE_BUILD_TYPE=MinSizeRel -DDYN_OPENAL=NO -DDYN_SNDFILE=NO -DDYN_MPG123=NO -DDYN_FLUIDSYNTH=NO"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- llvm-toolchain-xenial-8
packages:
- clang-8
- libsdl2-dev
- libgme-dev
- libopenal-dev
- libmpg123-dev
- libsndfile-dev
- libfluidsynth-dev
- libgtk-3-dev
before_install:
- if [ -n "$GCC_VERSION" ]; then export CC="gcc-${GCC_VERSION}" CXX="g++-${GCC_VERSION}"; fi
- if [ -n "$CLANG_VERSION" ]; then export CC="clang-${CLANG_VERSION}" CXX="clang++-${CLANG_VERSION}"; fi
- $CC --version
- $CXX --version
script:
- echo ${TRAVIS_BUILD_DIR}
- mkdir build
- cd build
- >
cmake ${CMAKE_OPTIONS} \
-DFORCE_INTERNAL_ZLIB=YES \
-DFORCE_INTERNAL_JPEG=YES \
-DFORCE_INTERNAL_BZIP2=YES \
-DFORCE_INTERNAL_GME=YES \
-DPK3_QUIET_ZIPDIR=YES \
..
- if [[ $TRAVIS_OS_NAME == 'windows' ]]; then cmake --build . --config Release -- -maxcpucount -verbosity:minimal; fi
- if [[ $TRAVIS_OS_NAME != 'windows' ]]; then cmake --build . -- --jobs=2 --keep-going; fi
notifications:
email: false

View File

@ -1,415 +0,0 @@
cmake_minimum_required( VERSION 2.8.7 )
project(LZDoom)
if( COMMAND cmake_policy )
if( POLICY CMP0011 )
cmake_policy( SET CMP0011 NEW )
endif()
if( POLICY CMP0054 )
cmake_policy( SET CMP0054 NEW )
endif()
endif()
list( APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake )
include( FindPackageHandleStandardArgs )
# Produce a warning if XP support will be missing when building a 32 bit target for MSVC.
if( MSVC )
if(NOT "${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
list( APPEND WINXP_TOOLSETS v140_xp v141_xp)
list( FIND WINXP_TOOLSETS "${CMAKE_GENERATOR_TOOLSET}" HAVE_WINXP_SUPPORT)
if( HAVE_WINXP_SUPPORT EQUAL -1 )
string( REPLACE ";" " or " WINXP_TOOLSETS_STR "${WINXP_TOOLSETS}" )
message( WARNING "This project supports Windows XP but you must set the optional toolset to ${WINXP_TOOLSETS_STR} manually to have it in your build!\n"
"Assign toolset's name to CMAKE_GENERATOR_TOOLSET variable or use -T <toolset> from the command prompt." )
endif()
endif()
endif()
# Support cross compiling
option( FORCE_CROSSCOMPILE "Turn on cross compiling." NO )
if( FORCE_CROSSCOMPILE )
set( CMAKE_CROSSCOMPILING TRUE )
endif()
if(CMAKE_CROSSCOMPILING)
set(IMPORT_EXECUTABLES "IMPORTFILE-NOTFOUND" CACHE FILEPATH "Export file from native build.")
include(${IMPORT_EXECUTABLES})
endif()
# Recursive function to place PK3 archive source files into a hierarchy of source file in the IDE
function( assort_pk3_source_folder FOLDER_NAME PK3_DIR )
# Assort source files into folders in the IDE
file(GLOB PK3_SRCS ${PK3_DIR}/*) # Create list of all files in this folder
foreach(PK3_SRC ${PK3_SRCS})
# If there are subfolders, recurse into them
if(IS_DIRECTORY ${PK3_SRC})
get_filename_component(DIRNAME ${PK3_SRC} NAME)
# Exclude folder from list of source files
list(REMOVE_ITEM PK3_SRCS ${PK3_SRC})
# Recurse deeper into the filesystem folder tree
assort_pk3_source_folder( ${FOLDER_NAME}\\${DIRNAME} ${PK3_SRC} )
endif()
# Assign IDE group for current top-level source files
source_group(${FOLDER_NAME} FILES ${PK3_SRCS})
endforeach()
endfunction()
option( PK3_QUIET_ZIPDIR "Do not list files processed by zipdir" NO )
if( PK3_QUIET_ZIPDIR )
set( PK3_ZIPDIR_OPTIONS "-q" )
endif()
# Simplify pk3 building, add_pk3(filename srcdirectory)
function( add_pk3 PK3_NAME PK3_DIR )
# Generate target name. Just use "pk3" for main pk3 target.
string( REPLACE "." "_" PK3_TARGET ${PK3_NAME} )
if( NOT ZDOOM_OUTPUT_OLDSTYLE )
add_custom_command( OUTPUT ${ZDOOM_OUTPUT_DIR}/${PK3_NAME}
COMMAND zipdir -udf ${PK3_ZIPDIR_OPTIONS} ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} ${PK3_DIR}
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} $<TARGET_FILE_DIR:zdoom>/${PK3_NAME}
DEPENDS zipdir )
else()
add_custom_command( OUTPUT ${ZDOOM_OUTPUT_DIR}/${PK3_NAME}
COMMAND zipdir -udf ${PK3_ZIPDIR_OPTIONS} ${ZDOOM_OUTPUT_DIR}/${PK3_NAME} ${PK3_DIR}
DEPENDS zipdir )
endif()
# Create a list of source files for this PK3, for use in the IDE
# Phase 1: Create a list of all source files for this PK3 archive, except
# for a couple of strife image file names that confuse CMake.
file(GLOB_RECURSE PK3_SRCS ${PK3_DIR}/*)
# Exclude from the source list some gzdoom .png files with brackets in the
# file names here, because they confuse CMake.
# This only affects the list of source files shown in the IDE.
# It does not actually remove the files from the PK3 archive.
# First replace that toxic bracket character with something we can handle
string(REPLACE "[" confusing_bracket PK3_SRCS "${PK3_SRCS}")
string(REPLACE "]" confusing_bracket PK3_SRCS "${PK3_SRCS}")
foreach(PK3_SRC ${PK3_SRCS}) # All source files at all levels
# Exclude those quarantined source file source file names that once had a bracket
if(${PK3_SRC} MATCHES confusing_bracket)
# message(STATUS "Ignoring PK3 file name containing brackets "${PK3_SRC})
list(REMOVE_ITEM PK3_SRCS ${PK3_SRC})
endif()
endforeach()
# Phase 2: Create the PK3 build rule, including the source file list for the IDE
# Touch the zipdir executable here so that the pk3s are forced to
# rebuild each time since their dependency has "changed."
add_custom_target( ${PK3_TARGET} ALL
COMMAND ${CMAKE_COMMAND} -E touch $<TARGET_FILE:zipdir>
DEPENDS ${ZDOOM_OUTPUT_DIR}/${PK3_NAME}
SOURCES ${PK3_SRCS})
# Phase 3: Assign source files to a nice folder structure in the IDE
assort_pk3_source_folder("Source Files" ${PK3_DIR})
# Phase 4: Add the resulting PK3 to the install target.
if( WIN32 )
set( INSTALL_PK3_PATH . CACHE STRING "Directory where zdoom.pk3 will be placed during install." )
else()
set( INSTALL_PK3_PATH share/games/doom CACHE STRING "Directory where zdoom.pk3 will be placed during install." )
endif()
install(FILES "${PROJECT_BINARY_DIR}/${PK3_NAME}"
DESTINATION ${INSTALL_PK3_PATH}
COMPONENT "Game resources")
endfunction()
# Macro for building libraries without debugging information
macro( make_release_only )
set( CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_RELEASE} )
set( CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELEASE} )
string( REPLACE "/MT " "/MTd " CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_RELEASE} )
set( CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_RELEASE} )
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELEASE} )
string( REPLACE "/MT " "/MTd " CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_RELEASE} )
endmacro()
IF( NOT CMAKE_BUILD_TYPE )
SET( CMAKE_BUILD_TYPE Debug CACHE STRING
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
FORCE )
ENDIF()
set( ZDOOM_OUTPUT_DIR ${CMAKE_BINARY_DIR} CACHE PATH "Directory where zdoom.pk3 and the executable will be created." )
set( ZDOOM_EXE_NAME "lzdoom" CACHE FILEPATH "Name of the executable to create" )
if( MSVC )
# Allow the user to use ZDOOM_OUTPUT_DIR as a single release point.
# Use zdoom, zdoomd, zdoom64, and zdoomd64 for the binary names
option( ZDOOM_OUTPUT_OLDSTYLE "Don't use Release/Debug directories." OFF )
else()
set( ZDOOM_OUTPUT_OLDSTYLE OFF )
endif()
# Replacement variables for a possible long list of C/C++ compilers compatible with GCC
if( "${CMAKE_C_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" )
set( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE TRUE )
else()
set( ZD_CMAKE_COMPILER_IS_GNUC_COMPATIBLE FALSE )
endif()
if( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )
set( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE TRUE )
else()
set( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE FALSE )
endif()
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set( PROFILE 0 CACHE BOOL "Enable profiling with gprof for Debug and RelWithDebInfo build types." )
endif()
option( NO_OPENAL "Disable OpenAL sound support" OFF )
find_package( BZip2 )
find_package( JPEG )
find_package( ZLIB )
include( TargetArch )
target_architecture(ZDOOM_TARGET_ARCH)
if( ${ZDOOM_TARGET_ARCH} MATCHES "x86_64" )
set( HAVE_VM_JIT ON )
endif()
# no, we're not using external asmjit for now, we made too many modifications to our's.
# if the asmjit author uses our changes then we'll update this.
#if( ${HAVE_VM_JIT} )
# find_package( asmjit )
#endif()
# GME
#find_path( GME_INCLUDE_DIR gme/gme.h )
#find_library( GME_LIBRARIES gme )
#mark_as_advanced( GME_INCLUDE_DIR GME_LIBRARIES )
#FIND_PACKAGE_HANDLE_STANDARD_ARGS( GME
# REQUIRED_VARS GME_LIBRARIES GME_INCLUDE_DIR
#)
if( MSVC )
# Eliminate unreferenced functions and data
# Perform identical COMDAT folding
set( REL_LINKER_FLAGS "/opt:ref /opt:icf /nodefaultlib:msvcrt /TSAWARE /LARGEADDRESSAWARE" )
# String pooling
# Function-level linking
# Disable run-time type information
set( ALL_C_FLAGS "/GF /Gy /GR-" )
# Use SSE 2 as minimum always as the true color drawers needs it for __vectorcall
#set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2") # This is already the default
# if( CMAKE_SIZEOF_VOID_P MATCHES "4")
# # SSE2 option (to allow x87 in 32 bit and disallow extended feature sets which have not yet been checked for precision)
# option (ZDOOM_USE_SSE2 "Use SSE2 instruction set")
# if (ZDOOM_USE_SSE2)
# set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2")
# else ()
# if (MSVC_VERSION GREATER 1699)
# # On Visual C++ 2012 and later SSE2 is the default, so we need to switch it off explicitly
# set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:IA32")
# endif ()
# endif ()
# else()
# set( ALL_C_FLAGS "${ALL_C_FLAGS} /arch:SSE2")
# endif()
# Avoid CRT DLL dependancies in release builds, optionally generate assembly output for checking crash locations.
option( ZDOOM_GENERATE_ASM "Generate assembly output." OFF )
if( ZDOOM_GENERATE_ASM )
set( REL_C_FLAGS "/MT /Oy /Oi /FAcs" )
else()
set( REL_C_FLAGS "/MT /Oy /Oi" )
endif()
# Debug allocations in debug builds
set( DEB_C_FLAGS "/D _CRTDBG_MAP_ALLOC /MTd" )
# Disable warnings for unsecure CRT functions from VC8+
set( ALL_C_FLAGS "${ALL_C_FLAGS} /wd4996 /DUNICODE /D_UNICODE" )
# The CMake configurations set /GR and /MD by default, which conflict with our settings.
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE} )
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL} )
string(REPLACE "/MD " " " CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} )
string(REPLACE "/Ob1 " "/Ob2 " CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO} )
string(REPLACE "/MDd " " " CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG} )
string(REPLACE "/MD " " " CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE} )
string(REPLACE "/MD " " " CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_MINSIZEREL} )
string(REPLACE "/MD " " " CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO} )
string(REPLACE "/MDd " " " CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG} )
string(REPLACE " /GR" " " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} )
else()
set( REL_LINKER_FLAGS "" )
set( ALL_C_FLAGS "-ffp-contract=off" )
if ( UNIX )
include(CheckSymbolExists)
check_symbol_exists( "fts_set" "fts.h" HAVE_FTS )
if ( NOT HAVE_FTS )
include ( FindPkgConfig )
pkg_check_modules( MUSL_FTS musl-fts )
if ( MUSL_FTS_FOUND )
set ( ALL_C_FLAGS "${ALL_C_FLAGS} ${MUSL_FTS_LDFLAGS}" )
else ( MUSL_FTS_FOUND )
message (ERROR "fts_* functions not found in the system" )
endif ( MUSL_FTS_FOUND )
endif ( NOT HAVE_FTS )
endif ( UNIX )
set( REL_C_FLAGS "" )
set( DEB_C_FLAGS "" )
if( APPLE )
if( CMAKE_CXX_COMPILER_ID STREQUAL "Clang" )
# With standard Apple tools -stdlib=libc++ needs to be specified in order to get
# C++11 support using SDKs 10.7 and 10.8.
set( CMAKE_CXX_FLAGS "-stdlib=libc++ ${CMAKE_CXX_FLAGS}" )
set( CMAKE_EXE_LINKER_FLAGS "-stdlib=libc++ ${CMAKE_EXE_LINKER_FLAGS}" )
elseif( CMAKE_CXX_COMPILER_ID STREQUAL "GNU" )
# If we're compiling with a custom GCC on the Mac (which we know since g++-4.2 doesn't support C++11) statically link libgcc.
set( ALL_C_FLAGS "-static-libgcc" )
endif()
elseif( NOT MINGW )
# Generic GCC/Clang requires position independent executable to be enabled explicitly
set( ALL_C_FLAGS "${ALL_C_FLAGS} -fPIE" )
set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pie" )
endif( APPLE )
endif()
set( CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${REL_LINKER_FLAGS}" )
set( CMAKE_EXE_LINKER_FLAGS_MINSIZEREL "${CMAKE_EXE_LINKER_FLAGS_MINSIZEREL} ${REL_LINKER_FLAGS}" )
set( CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} ${REL_LINKER_FLAGS}" )
set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${ALL_C_FLAGS}" )
set( CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${REL_C_FLAGS}" )
set( CMAKE_C_FLAGS_MINSIZEREL "${CMAKE_C_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" )
set( CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
set( CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ALL_C_FLAGS}" )
set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${REL_C_FLAGS}" )
set( CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS_MINSIZEREL} ${REL_C_FLAGS}" )
set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${REL_C_FLAGS}" )
set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${DEB_C_FLAGS} -D_DEBUG" )
option(FORCE_INTERNAL_ZLIB "Use internal zlib")
option(FORCE_INTERNAL_JPEG "Use internal jpeg")
option(FORCE_INTERNAL_BZIP2 "Use internal bzip2")
option(FORCE_INTERNAL_GME "Use internal gme" ON)
mark_as_advanced( FORCE_INTERNAL_GME )
option(FORCE_INTERNAL_ASMJIT "Use internal asmjit" ON)
mark_as_advanced( FORCE_INTERNAL_ASMJIT )
# Fast math flags, required by some subprojects
set( ZD_FASTMATH_FLAG "" )
if( ZD_CMAKE_COMPILER_IS_GNUCXX_COMPATIBLE )
set( ZD_FASTMATH_FLAG "-ffast-math -ffp-contract=fast" )
elseif( MSVC )
set( ZD_FASTMATH_FLAG "/fp:fast" )
endif()
if( ZLIB_FOUND AND NOT FORCE_INTERNAL_ZLIB )
message( STATUS "Using system zlib, includes found at ${ZLIB_INCLUDE_DIR}" )
else()
message( STATUS "Using internal zlib" )
set( SKIP_INSTALL_ALL TRUE ) # Avoid installing zlib alongside zdoom
add_subdirectory( zlib )
set( ZLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/zlib )
set( ZLIB_LIBRARIES z )
set( ZLIB_LIBRARY z )
endif()
if( HAVE_VM_JIT AND UNIX )
check_symbol_exists( "backtrace" "execinfo.h" HAVE_BACKTRACE )
if( NOT HAVE_BACKTRACE )
set( CMAKE_REQUIRED_FLAGS "-lexecinfo" )
check_symbol_exists( "backtrace" "execinfo.h" HAVE_LIBEXECINFO )
if( HAVE_LIBEXECINFO )
set( ALL_C_FLAGS "${ALL_C_FLAGS} -lexecinfo" )
else( HAVE_LIBEXECINFO )
set( HAVE_VM_JIT NO )
endif( HAVE_LIBEXECINFO )
endif( NOT HAVE_BACKTRACE )
endif( HAVE_VM_JIT AND UNIX )
if( ${HAVE_VM_JIT} )
if( ASMJIT_FOUND AND NOT FORCE_INTERNAL_ASMJIT )
message( STATUS "Using system asmjit, includes found at ${ASMJIT_INCLUDE_DIR}" )
else()
message( STATUS "Using internal asmjit" )
set( SKIP_INSTALL_ALL TRUE ) # Avoid installing asmjit alongside zdoom
add_subdirectory( asmjit )
set( ASMJIT_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/asmjit )
set( ASMJIT_LIBRARIES asmjit )
set( ASMJIT_LIBRARY asmjit )
endif()
endif()
if( JPEG_FOUND AND NOT FORCE_INTERNAL_JPEG )
message( STATUS "Using system jpeg library, includes found at ${JPEG_INCLUDE_DIR}" )
else()
message( STATUS "Using internal jpeg library" )
add_subdirectory( jpeg )
set( JPEG_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/jpeg )
set( JPEG_LIBRARIES jpeg )
set( JPEG_LIBRARY jpeg )
endif()
if( BZIP2_FOUND AND NOT FORCE_INTERNAL_BZIP2 )
message( STATUS "Using system bzip2 library, includes found at ${BZIP2_INCLUDE_DIR}" )
else()
message( STATUS "Using internal bzip2 library" )
add_subdirectory( bzip2 )
set( BZIP2_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bzip2" )
set( BZIP2_LIBRARIES bz2 )
set( BZIP2_LIBRARY bz2 )
endif()
if( GME_FOUND AND NOT FORCE_INTERNAL_GME )
message( STATUS "Using system gme library, includes found at ${GME_INCLUDE_DIR}" )
else()
message( STATUS "Using internal gme library" )
# Use MAME as it's balanced emulator: well-accurate, but doesn't eats lot of CPU
# Nuked OPN2 is very accurate emulator, but it eats too much CPU for the workflow
set( GME_YM2612_EMU "MAME" )
add_subdirectory( game-music-emu )
set( GME_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/game-music-emu" )
set( GME_LIBRARIES gme )
endif()
set( LZMA_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/lzma/C" )
if( NOT CMAKE_CROSSCOMPILING )
if( NOT CROSS_EXPORTS )
set( CROSS_EXPORTS "" )
endif()
endif()
# Install the entire docs directory in the distributed zip package
if( WIN32 )
set( INSTALL_DOCS_PATH docs CACHE STRING "Directory where the documentation will be placed during install." )
else()
set( INSTALL_DOCS_PATH share/doc/${ZDOOM_EXE_NAME} CACHE STRING "Directory where the zdoom documentation will be placed during install." )
endif()
install(DIRECTORY docs/
DESTINATION ${INSTALL_DOCS_PATH}
COMPONENT "Documentation")
add_subdirectory( lzma )
add_subdirectory( tools )
add_subdirectory( dumb )
add_subdirectory( gdtoa )
add_subdirectory( wadsrc )
add_subdirectory( wadsrc_bm )
add_subdirectory( wadsrc_lights )
add_subdirectory( wadsrc_extra )
add_subdirectory( src )
if( NOT CMAKE_CROSSCOMPILING )
export(TARGETS ${CROSS_EXPORTS} FILE "${CMAKE_BINARY_DIR}/ImportExecutables.cmake" )
endif()

View File

@ -1,28 +0,0 @@
# Welcome to LZDoom!
[![Build Status](https://ci.appveyor.com/api/projects/status/github/drfrag666/gzdoom?branch=g3.3mgw&svg=true)](https://ci.appveyor.com/project/drfrag666/gzdoom) [![Build Status](https://travis-ci.org/drfrag666/gzdoom.svg?branch=g3.3mgw)](https://travis-ci.org/drfrag666/gzdoom)
## LZDoom is a fork of GZDoom 3.3 compiling with MinGW and running on older non SSE2 cpus while keeping the DDRAW and D3D backends for compatibility.
Copyright (c) 1998-2019 ZDoom + GZDoom teams, and contributors
Doom Source (c) 1997 id Software, Raven Software, and contributors
Please see license files for individual contributor licenses
Special thanks to Coraline of the 3DGE team for allowing us to use her README.md as a template for this one.
### Licensed under the GPL v3
##### https://www.gnu.org/licenses/quick-guide-gplv3.en.html
---
## How to build GZDoom
To build GZDoom, please see the [wiki](https://zdoom.org/wiki/) and see the "Programmer's Corner" on the bottom-right corner of the page to build for your platform.
GZDoom repo: https://github.com/coelckers/gzdoom
## Other forks/branches
- legacy: Official GZDoom vintage build for GL 2 hardware. - gzdoom32: ZDoom32. - gzdoomle: ZDoom LE (Legacy Edition).
For more info see old README.md: https://github.com/drfrag666/gzdoom/blob/gzdoom32/README.md

View File

@ -1,23 +0,0 @@
# - Find fluidsynth
# Find the native fluidsynth includes and library
#
# FLUIDSYNTH_INCLUDE_DIR - where to find fluidsynth.h
# FLUIDSYNTH_LIBRARIES - List of libraries when using fluidsynth.
# FLUIDSYNTH_FOUND - True if fluidsynth found.
IF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES)
# Already in cache, be silent
SET(FluidSynth_FIND_QUIETLY TRUE)
ENDIF (FLUIDSYNTH_INCLUDE_DIR AND FLUIDSYNTH_LIBRARIES)
FIND_PATH(FLUIDSYNTH_INCLUDE_DIR fluidsynth.h)
FIND_LIBRARY(FLUIDSYNTH_LIBRARIES NAMES fluidsynth )
MARK_AS_ADVANCED( FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR )
# handle the QUIETLY and REQUIRED arguments and set FLUIDSYNTH_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(FluidSynth DEFAULT_MSG FLUIDSYNTH_LIBRARIES FLUIDSYNTH_INCLUDE_DIR)

View File

@ -1,28 +0,0 @@
# - Find mpg123
# Find the native mpg123 includes and library
#
# MPG123_INCLUDE_DIR - where to find mpg123.h
# MPG123_LIBRARIES - List of libraries when using mpg123.
# MPG123_FOUND - True if mpg123 found.
IF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES)
# Already in cache, be silent
SET(MPG123_FIND_QUIETLY TRUE)
ENDIF(MPG123_INCLUDE_DIR AND MPG123_LIBRARIES)
FIND_PATH(MPG123_INCLUDE_DIR mpg123.h
PATHS "${MPG123_DIR}"
PATH_SUFFIXES include
)
FIND_LIBRARY(MPG123_LIBRARIES NAMES mpg123 mpg123-0
PATHS "${MPG123_DIR}"
PATH_SUFFIXES lib
)
# MARK_AS_ADVANCED(MPG123_LIBRARIES MPG123_INCLUDE_DIR)
# handle the QUIETLY and REQUIRED arguments and set MPG123_FOUND to TRUE if
# all listed variables are TRUE
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(MPG123 DEFAULT_MSG MPG123_LIBRARIES MPG123_INCLUDE_DIR)

View File

@ -1,182 +0,0 @@
# Locate SDL2 library
# This module defines
# SDL2_LIBRARY, the name of the library to link against
# SDL2_FOUND, if false, do not try to link to SDL2
# SDL2_INCLUDE_DIR, where to find SDL.h
#
# This module responds to the the flag:
# SDL2_BUILDING_LIBRARY
# If this is defined, then no SDL2_main will be linked in because
# only applications need main().
# Otherwise, it is assumed you are building an application and this
# module will attempt to locate and set the the proper link flags
# as part of the returned SDL2_LIBRARY variable.
#
# Don't forget to include SDL2main.h and SDL2main.m your project for the
# OS X framework based version. (Other versions link to -lSDL2main which
# this module will try to find on your behalf.) Also for OS X, this
# module will automatically add the -framework Cocoa on your behalf.
#
#
# Additional Note: If you see an empty SDL2_LIBRARY_TEMP in your configuration
# and no SDL2_LIBRARY, it means CMake did not find your SDL2 library
# (SDL2.dll, libsdl2.so, SDL2.framework, etc).
# Set SDL2_LIBRARY_TEMP to point to your SDL2 library, and configure again.
# Similarly, if you see an empty SDL2MAIN_LIBRARY, you should set this value
# as appropriate. These values are used to generate the final SDL2_LIBRARY
# variable, but when these values are unset, SDL2_LIBRARY does not get created.
#
#
# $SDL2DIR is an environment variable that would
# correspond to the ./configure --prefix=$SDL2DIR
# used in building SDL2.
# l.e.galup 9-20-02
#
# Modified by Eric Wing.
# Added code to assist with automated building by using environmental variables
# and providing a more controlled/consistent search behavior.
# Added new modifications to recognize OS X frameworks and
# additional Unix paths (FreeBSD, etc).
# Also corrected the header search path to follow "proper" SDL2 guidelines.
# Added a search for SDL2main which is needed by some platforms.
# Added a search for threads which is needed by some platforms.
# Added needed compile switches for MinGW.
#
# On OSX, this will prefer the Framework version (if found) over others.
# People will have to manually change the cache values of
# SDL2_LIBRARY to override this selection or set the CMake environment
# CMAKE_INCLUDE_PATH to modify the search paths.
#
# Note that the header path has changed from SDL2/SDL.h to just SDL.h
# This needed to change because "proper" SDL2 convention
# is #include "SDL.h", not <SDL2/SDL.h>. This is done for portability
# reasons because not all systems place things in SDL2/ (see FreeBSD).
#
# Ported by Johnny Patterson. This is a literal port for SDL2 of the FindSDL.cmake
# module with the minor edit of changing "SDL" to "SDL2" where necessary. This
# was not created for redistribution, and exists temporarily pending official
# SDL2 CMake modules.
#=============================================================================
# Copyright 2003-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
FIND_PATH(SDL2_INCLUDE_DIR SDL.h
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES include/SDL2 include
PATHS
~/Library/Frameworks
/Library/Frameworks
/usr/local/include/SDL2
/usr/include/SDL2
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
/boot/system/develop/headers/SDL2 #Hiaku OS
)
#MESSAGE("SDL2_INCLUDE_DIR is ${SDL2_INCLUDE_DIR}")
FIND_LIBRARY(SDL2_LIBRARY_TEMP
NAMES SDL2
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES lib64 lib
PATHS
/sw
/opt/local
/opt/csw
/opt
/system/lib #Hiaku OS
)
#MESSAGE("SDL2_LIBRARY_TEMP is ${SDL2_LIBRARY_TEMP}")
IF(NOT SDL2_BUILDING_LIBRARY)
IF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
# Non-OS X framework versions expect you to also dynamically link to
# SDL2main. This is mainly for Windows and OS X. Other (Unix) platforms
# seem to provide SDL2main for compatibility even though they don't
# necessarily need it.
FIND_LIBRARY(SDL2MAIN_LIBRARY
NAMES SDL2main
HINTS
$ENV{SDL2DIR}
PATH_SUFFIXES lib64 lib
PATHS
/sw
/opt/local
/opt/csw
/opt
)
ENDIF(NOT ${SDL2_INCLUDE_DIR} MATCHES ".framework")
ENDIF(NOT SDL2_BUILDING_LIBRARY)
# SDL2 may require threads on your system.
# The Apple build may not need an explicit flag because one of the
# frameworks may already provide it.
# But for non-OSX systems, I will use the CMake Threads package.
IF(NOT APPLE)
FIND_PACKAGE(Threads)
ENDIF(NOT APPLE)
# MinGW needs an additional library, mwindows
# It's total link flags should look like -lmingw32 -lSDL2main -lSDL2 -lmwindows
# (Actually on second look, I think it only needs one of the m* libraries.)
IF(MINGW)
SET(MINGW32_LIBRARY mingw32 CACHE STRING "mwindows for MinGW")
ENDIF(MINGW)
SET(SDL2_FOUND "NO")
IF(SDL2_LIBRARY_TEMP)
# For SDL2main
IF(NOT SDL2_BUILDING_LIBRARY)
IF(SDL2MAIN_LIBRARY)
SET(SDL2_LIBRARY_TEMP ${SDL2MAIN_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(SDL2MAIN_LIBRARY)
ENDIF(NOT SDL2_BUILDING_LIBRARY)
# For OS X, SDL2 uses Cocoa as a backend so it must link to Cocoa.
# CMake doesn't display the -framework Cocoa string in the UI even
# though it actually is there if I modify a pre-used variable.
# I think it has something to do with the CACHE STRING.
# So I use a temporary variable until the end so I can set the
# "real" variable in one-shot.
IF(APPLE)
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} "-framework Cocoa")
ENDIF(APPLE)
# For threads, as mentioned Apple doesn't need this.
# In fact, there seems to be a problem if I used the Threads package
# and try using this line, so I'm just skipping it entirely for OS X.
IF(NOT APPLE)
SET(SDL2_LIBRARY_TEMP ${SDL2_LIBRARY_TEMP} ${CMAKE_THREAD_LIBS_INIT})
ENDIF(NOT APPLE)
# For MinGW library
IF(MINGW)
SET(SDL2_LIBRARY_TEMP ${MINGW32_LIBRARY} ${SDL2_LIBRARY_TEMP})
ENDIF(MINGW)
# Set the final string here so the GUI reflects the final state.
SET(SDL2_LIBRARY ${SDL2_LIBRARY_TEMP} CACHE STRING "Where the SDL2 Library can be found")
# Set the temp variable to INTERNAL so it is not seen in the CMake GUI
SET(SDL2_LIBRARY_TEMP "${SDL2_LIBRARY_TEMP}" CACHE INTERNAL "")
SET(SDL2_FOUND "YES")
ENDIF(SDL2_LIBRARY_TEMP)
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SDL2
REQUIRED_VARS SDL2_LIBRARY SDL2_INCLUDE_DIR)

View File

@ -1,29 +0,0 @@
# - Try to find SndFile
# Once done this will define
#
# SNDFILE_FOUND - system has SndFile
# SNDFILE_INCLUDE_DIRS - the SndFile include directory
# SNDFILE_LIBRARIES - Link these to use SndFile
#
# Copyright © 2006 Wengo
# Copyright © 2009 Guillaume Martres
#
# Redistribution and use is allowed according to the terms of the New
# BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
find_path(SNDFILE_INCLUDE_DIR NAMES sndfile.h)
find_library(SNDFILE_LIBRARY NAMES sndfile sndfile-1)
set(SNDFILE_INCLUDE_DIRS ${SNDFILE_INCLUDE_DIR})
set(SNDFILE_LIBRARIES ${SNDFILE_LIBRARY})
INCLUDE(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set SNDFILE_FOUND to TRUE if
# all listed variables are TRUE
FIND_PACKAGE_HANDLE_STANDARD_ARGS(SndFile DEFAULT_MSG SNDFILE_LIBRARY SNDFILE_INCLUDE_DIR)
# show the SNDFILE_INCLUDE_DIRS and SNDFILE_LIBRARIES variables only in the advanced view
mark_as_advanced(SNDFILE_INCLUDE_DIRS SNDFILE_LIBRARIES)

View File

@ -1,157 +0,0 @@
# Copyright (c) 2012 Petroules Corporation. All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation and/or
# other materials provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
# OF SUCH DAMAGE.
# Based on the Qt 5 processor detection code, so should be very accurate
# https://qt.gitorious.org/qt/qtbase/blobs/master/src/corelib/global/qprocessordetection.h
# Currently handles arm (v5, v6, v7), x86 (32/64), ia64, and ppc (32/64)
# Regarding POWER/PowerPC, just as is noted in the Qt source,
# "There are many more known variants/revisions that we do not handle/detect."
set(archdetect_c_code "
#if defined(__arm__) || defined(__TARGET_ARCH_ARM)
#if defined(__ARM_ARCH_7__) \\
|| defined(__ARM_ARCH_7A__) \\
|| defined(__ARM_ARCH_7R__) \\
|| defined(__ARM_ARCH_7M__) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 7)
#error cmake_ARCH armv7
#elif defined(__ARM_ARCH_6__) \\
|| defined(__ARM_ARCH_6J__) \\
|| defined(__ARM_ARCH_6T2__) \\
|| defined(__ARM_ARCH_6Z__) \\
|| defined(__ARM_ARCH_6K__) \\
|| defined(__ARM_ARCH_6ZK__) \\
|| defined(__ARM_ARCH_6M__) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 6)
#error cmake_ARCH armv6
#elif defined(__ARM_ARCH_5TEJ__) \\
|| (defined(__TARGET_ARCH_ARM) && __TARGET_ARCH_ARM-0 >= 5)
#error cmake_ARCH armv5
#else
#error cmake_ARCH arm
#endif
#elif defined(__i386) || defined(__i386__) || defined(_M_IX86)
#error cmake_ARCH i386
#elif defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)
#error cmake_ARCH x86_64
#elif defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
#error cmake_ARCH ia64
#elif defined(__ppc__) || defined(__ppc) || defined(__powerpc__) \\
|| defined(_ARCH_COM) || defined(_ARCH_PWR) || defined(_ARCH_PPC) \\
|| defined(_M_MPPC) || defined(_M_PPC)
#if defined(__ppc64__) || defined(__powerpc64__) || defined(__64BIT__)
#error cmake_ARCH ppc64
#else
#error cmake_ARCH ppc
#endif
#endif
#error cmake_ARCH unknown
")
# Set ppc_support to TRUE before including this file or ppc and ppc64
# will be treated as invalid architectures since they are no longer supported by Apple
function(target_architecture output_var)
if(APPLE AND CMAKE_OSX_ARCHITECTURES)
# On OS X we use CMAKE_OSX_ARCHITECTURES *if* it was set
# First let's normalize the order of the values
# Note that it's not possible to compile PowerPC applications if you are using
# the OS X SDK version 10.6 or later - you'll need 10.4/10.5 for that, so we
# disable it by default
# See this page for more information:
# http://stackoverflow.com/questions/5333490/how-can-we-restore-ppc-ppc64-as-well-as-full-10-4-10-5-sdk-support-to-xcode-4
# Architecture defaults to i386 or ppc on OS X 10.5 and earlier, depending on the CPU type detected at runtime.
# On OS X 10.6+ the default is x86_64 if the CPU supports it, i386 otherwise.
foreach(osx_arch ${CMAKE_OSX_ARCHITECTURES})
if("${osx_arch}" STREQUAL "ppc" AND ppc_support)
set(osx_arch_ppc TRUE)
elseif("${osx_arch}" STREQUAL "i386")
set(osx_arch_i386 TRUE)
elseif("${osx_arch}" STREQUAL "x86_64")
set(osx_arch_x86_64 TRUE)
elseif("${osx_arch}" STREQUAL "ppc64" AND ppc_support)
set(osx_arch_ppc64 TRUE)
else()
message(FATAL_ERROR "Invalid OS X arch name: ${osx_arch}")
endif()
endforeach()
# Now add all the architectures in our normalized order
if(osx_arch_ppc)
list(APPEND ARCH ppc)
endif()
if(osx_arch_i386)
list(APPEND ARCH i386)
endif()
if(osx_arch_x86_64)
list(APPEND ARCH x86_64)
endif()
if(osx_arch_ppc64)
list(APPEND ARCH ppc64)
endif()
else()
file(WRITE "${CMAKE_BINARY_DIR}/arch.c" "${archdetect_c_code}")
enable_language(C)
# Detect the architecture in a rather creative way...
# This compiles a small C program which is a series of ifdefs that selects a
# particular #error preprocessor directive whose message string contains the
# target architecture. The program will always fail to compile (both because
# file is not a valid C program, and obviously because of the presence of the
# #error preprocessor directives... but by exploiting the preprocessor in this
# way, we can detect the correct target architecture even when cross-compiling,
# since the program itself never needs to be run (only the compiler/preprocessor)
try_run(
run_result_unused
compile_result_unused
"${CMAKE_BINARY_DIR}"
"${CMAKE_BINARY_DIR}/arch.c"
COMPILE_OUTPUT_VARIABLE ARCH
CMAKE_FLAGS CMAKE_OSX_ARCHITECTURES=${CMAKE_OSX_ARCHITECTURES}
)
# Parse the architecture name from the compiler output
string(REGEX MATCH "cmake_ARCH ([a-zA-Z0-9_]+)" ARCH "${ARCH}")
# Get rid of the value marker leaving just the architecture name
string(REPLACE "cmake_ARCH " "" ARCH "${ARCH}")
# If we are compiling with an unknown architecture this variable should
# already be set to "unknown" but in the case that it's empty (i.e. due
# to a typo in the code), then set it to unknown
if (NOT ARCH)
set(ARCH unknown)
endif()
endif()
set(${output_var} "${ARCH}" PARENT_SCOPE)
endfunction()

View File

@ -1,45 +0,0 @@
#
# Christoph Heindl 2010
# Precompiled Headers Demo
# http://cheind.wordpress.com
#
# Instructs the MSVC toolset to use the precompiled header PRECOMPILED_HEADER
# for each source file given in the collection named by SOURCE_VARIABLE_NAME.
function(enable_precompiled_headers PRECOMPILED_HEADER SOURCE_VARIABLE_NAME)
if(MSVC)
set(files ${${SOURCE_VARIABLE_NAME}})
# Generate precompiled header translation unit
get_filename_component(pch_basename ${PRECOMPILED_HEADER} NAME_WE)
set(pch_abs ${CMAKE_CURRENT_SOURCE_DIR}/${PRECOMPILED_HEADER})
set(pch_unity ${CMAKE_CURRENT_BINARY_DIR}/${pch_basename}.cpp)
set(pch_content "// Precompiled header unity generated by CMake\n#include <${pch_abs}>\n")
# Read .cpp if exists
if(EXISTS ${pch_unity})
file(READ ${pch_unity} pch_content_prev)
endif()
# Compare existing .cpp content with the actual one
if (pch_content_prev AND pch_content STREQUAL pch_content_prev)
unset(pch_content)
endif()
# Write .cpp if it's out-of-date
if (pch_content)
FILE(WRITE ${pch_unity} "${pch_content}")
endif()
set_source_files_properties(${pch_unity} PROPERTIES COMPILE_FLAGS "/Yc\"${pch_abs}\"")
# Update properties of source files to use the precompiled header.
# Additionally, force the inclusion of the precompiled header at beginning of each source file.
foreach(source_file ${files} )
set_source_files_properties(
${source_file}
PROPERTIES COMPILE_FLAGS
"/Yu\"${pch_abs}\" /FI\"${pch_abs}\""
)
endforeach(source_file)
# Finally, update the source file collection to contain the precompiled header translation unit
set(${SOURCE_VARIABLE_NAME} ${${SOURCE_VARIABLE_NAME}} ${pch_unity} PARENT_SCOPE)
endif(MSVC)
endfunction(enable_precompiled_headers)

View File

@ -1,162 +0,0 @@
DT
{
font-weight: bold;
}
DD
{
margin-bottom: 1em;
margin-left: 1.5em;
margin-right: 1.5em;
}
TH
{
text-align: left;
font-weight: bold;
padding-right: 2em;
vertical-align: top;
}
TD
{
text-align: left;
}
/* Command Descriptions */
DIV.c
{
border-right: 2px solid;
padding-right: 0.4em;
border-top: 1px solid;
margin-top: 1em;
padding-left: 0.4em;
font-weight: bold;
padding-bottom: 0.2em;
border-left: 1px solid;
padding-top: 0.2em;
border-bottom: 1px solid;
background-color: rgb(152,251,152);
margin-bottom: 0px;
}
DIV.b
{
border-right: 2px solid;
padding-right: 1.2em;
border-top: 1px;
padding-left: 1.2em;
padding-bottom: 0.5em;
border-left: 1px solid;
padding-top: 0.5em;
border-bottom: 2px solid;
background-color: rgb(240,255,240);
margin-top: 0px;
}
/* Variable Descriptions */
DIV.v, DIV.vf
{
border-right: 2px solid;
padding-right: 0.4em;
border-top: 1px solid;
margin-top: 1em;
padding-left: 0.4em;
font-weight: bold;
padding-bottom: 0.2em;
border-left: 1px solid;
padding-top: 0.2em;
border-bottom: 1px solid;
background-color: rgb(175,238,238);
}
DIV.vf
{
background-color: rgb(175,200,238);
}
DIV.t, DIV.tf
{
border-right: 2px solid;
padding-right: 1.2em;
border-top: 1px;
padding-left: 0.9em;
padding-bottom: 0.2em;
border-left: 1px solid;
padding-top: 0.2em;
border-bottom: 1px solid;
background-color: rgb(224,255,255);
}
DIV.tf
{
background-color: rgb(224,238,255);
}
DIV.d, DIV.df
{
border-right: 2px solid;
padding-right: 1.2em;
border-top: 2px;
padding-left: 1.2em;
padding-bottom: 0.5em;
border-left: 1px solid;
padding-top: 0.5em;
border-bottom: 2px solid;
background-color: rgb(240,255,255);
}
DIV.df
{
background-color: rgb(240,248,255);
}
P
{
margin-top: 1em;
margin-bottom: 0em;
}
A
{
color: Blue;
text-decoration: none;
}
A:hover
{
text-decoration: underline;
}
H1, H2
{
font-weight: bold;
left: -0.8em;
font-family: Verdana, Arial, Helvetica, Sans-Serif;
position: relative;
}
H3, H4
{
font-weight: bold;
font-family: Verdana, Arial, Helvetica, Sans-Serif;
left: 0em;
}
BODY
{
margin: 2em 2em 2em 2em;
background-color: white;
}
PRE
{
border: ridge 2px;
background-color: rgb(210,210,210);
padding: 1em 1em 1em 1em;
}
DIV.index
{
padding-right: 0.8em;
padding-left: 0.8em;
left: 0px;
float: left;
padding-bottom: 1em;
overflow: auto;
clip: rect(auto,auto,auto,auto);
padding-top: 0.5em;
position: absolute;
top: 0px;
background-color: #ffffcc;
border-right: solid 1px #808080;
border-bottom: solid 1px #808080;
}
DIV.main
{
margin-left: 11em;
height: 50%;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,34 +0,0 @@
The original Doom source code was released by id Software under the
GPL v2, but has been relicensed under the GPL v3 for GZDoom.
See gpl.txt
Parts of the voxel code in the software renderer use code from the
BUILD engine by Ken Silverman and are used under the terms of the
GPL v3 with permission.
The majority of original code uses a BSD-like lincese. See bsd.txt.
The OpenGL renderer is released under the LGPL v3, except some bits
of code that were inherited fro ZDoomGL.
Some code was taken from the Eternity Engine.
Copyright (c) James Haley, Stephen McGranahan, et al.
This software is based in part on the work of the Independent JPEG Group.
This software uses the 'zlib' general purpose compression library by
Jean-loup Gailly and Mark Adler.
This software uses the gdtoa package, see gdtoa.txt.
This software uses the game_music_emu library, which is covered by the GNU Lesser
General Public License. See lgpl.txt.
This software uses the "Dynamic Universal Music Bibliotheque" library for
MOD music playback. See dumb.txt for original license. The version used,
however, has been heavily modified from its original form and is the same
version used by the foobar2000 component foo_dumb as of mid-2008, found at
http://kode54.foobar2000.org/.
All script code in gzdoom.pk3 is licensed under the GPL v3 unless noted
otherwise.

View File

@ -1,27 +0,0 @@
**---------------------------------------------------------------------------
** Copyright 1998-2009 Randy Heit, Christoph Oelckers, et al.
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------

View File

@ -1,42 +0,0 @@
--------------------------------------------------------------------------
This program, "bzip2", the associated library "libbzip2", and all
documentation, are copyright (C) 1996-2010 Julian R Seward. All
rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. The origin of this software must not be misrepresented; you must
not claim that you wrote the original software. If you use this
software in a product, an acknowledgment in the product
documentation would be appreciated but is not required.
3. Altered source versions must be plainly marked as such, and must
not be misrepresented as being the original software.
4. The name of the author may not be used to endorse or promote
products derived from this software without specific prior written
permission.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Julian Seward, jseward@bzip.org
bzip2/libbzip2 version 1.0.6 of 6 September 2010
--------------------------------------------------------------------------

View File

@ -1,54 +0,0 @@
/* _______ ____ __ ___ ___
* \ _ \ \ / \ / \ \ / / ' ' '
* | | \ \ | | || | \/ | . .
* | | | | | | || ||\ /| |
* | | | | | | || || \/ | | ' ' '
* | | | | | | || || | | . .
* | |_/ / \ \__// || | |
* /_______/ynamic \____/niversal /__\ /____\usic /| . . ibliotheque
* / \
* / . \
* licence.txt - Conditions for use of DUMB. / / \ \
* | < / \_
* If you do not agree to these terms, please | \/ /\ /
* do not use DUMB. \_ / > /
* | \ / /
* Information in [brackets] is provided to aid | ' /
* interpretation of the licence. \__/
*/
Dynamic Universal Music Bibliotheque
Copyright (C) 2001-2003 Ben Davis, Robert J Ohannessian and Julien Cugniere
This software is provided 'as-is', without any express or implied warranty.
In no event shall the authors be held liable for any damages arising from the
use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a
product, you are requested to acknowledge its use in the product
documentation, along with details on where to get an unmodified version of
this software, but this is not a strict requirement.
[Note that the above point asks for a link to DUMB, not just a mention.
Googling for DUMB doesn't help much! The URL is "http://dumb.sf.net/".]
[The only reason why the link is not strictly required is that such a
requirement prevents DUMB from being used in projects with certain other
licences, notably the GPL. See http://www.gnu.org/philosophy/bsd.html .]
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed from or altered in any source distribution.
4. If you are using the Program in someone else's bedroom at any Monday
3:05 PM, you are not allowed to modify the Program for ten minutes. [This
clause provided by Inphernic; every licence should contain at least one
clause, the reasoning behind which is far from obvious.]

View File

@ -1,33 +0,0 @@
//----------------------------------------------------------------------------------
// File: es3-kepler\FXAA/FXAA3_11.h
// SDK Version: v3.00
// Email: gameworks@nvidia.com
// Site: http://developer.nvidia.com/
//
// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of NVIDIA CORPORATION nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//----------------------------------------------------------------------------------

View File

@ -1,27 +0,0 @@
/****************************************************************
The author of this software is David M. Gay.
Copyright (C) 1998 by Lucent Technologies
All Rights Reserved
Permission to use, copy, modify, and distribute this software and
its documentation for any purpose and without fee is hereby
granted, provided that the above copyright notice appear in all
copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of Lucent or any of its entities
not be used in advertising or publicity pertaining to
distribution of the software without specific, written prior
permission.
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
****************************************************************/

View File

@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View File

@ -1,841 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 240 KiB

View File

@ -1,23 +0,0 @@
cmake_minimum_required( VERSION 2.8.7 )
make_release_only()
use_fast_math()
add_definitions(-DADLMIDI_DISABLE_MIDI_SEQUENCER)
add_library( adl STATIC
adldata.cpp
adlmidi.cpp
adlmidi_load.cpp
adlmidi_midiplay.cpp
adlmidi_opl3.cpp
adlmidi_private.cpp
chips/dosbox/dbopl.cpp
chips/dosbox_opl3.cpp
chips/nuked/nukedopl3_174.c
chips/nuked/nukedopl3.c
chips/nuked_opl3.cpp
chips/nuked_opl3_v174.cpp
wopl/wopl_file.c
)
target_link_libraries( adl )

View File

@ -1,138 +0,0 @@
/*
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2016 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ADLDATA_H
#define ADLDATA_H
#include <string.h>
#include <stdint.h>
#include <cstring>
#pragma pack(push, 1)
#define ADLDATA_BYTE_COMPARABLE(T) \
inline bool operator==(const T &a, const T &b) \
{ return !memcmp(&a, &b, sizeof(T)); } \
inline bool operator!=(const T &a, const T &b) \
{ return !operator==(a, b); }
struct adldata
{
uint32_t modulator_E862, carrier_E862; // See below
uint8_t modulator_40, carrier_40; // KSL/attenuation settings
uint8_t feedconn; // Feedback/connection bits for the channel
int8_t finetune;
};
ADLDATA_BYTE_COMPARABLE(struct adldata)
struct adlinsdata
{
enum { Flag_Pseudo4op = 0x01, Flag_NoSound = 0x02, Flag_Real4op = 0x04 };
enum { Flag_RM_BassDrum = 0x08, Flag_RM_Snare = 0x10, Flag_RM_TomTom = 0x18,
Flag_RM_Cymbal = 0x20, Flag_RM_HiHat = 0x28, Mask_RhythmMode = 0x38 };
uint16_t adlno1, adlno2;
uint8_t tone;
uint8_t flags;
uint16_t ms_sound_kon; // Number of milliseconds it produces sound;
uint16_t ms_sound_koff;
int8_t midi_velocity_offset;
double voice2_fine_tune;
};
ADLDATA_BYTE_COMPARABLE(struct adlinsdata)
enum { adlNoteOnMaxTime = 40000 };
/**
* @brief Instrument data with operators included
*/
struct adlinsdata2
{
adldata adl[2];
uint8_t tone;
uint8_t flags;
uint16_t ms_sound_kon; // Number of milliseconds it produces sound;
uint16_t ms_sound_koff;
int8_t midi_velocity_offset;
double voice2_fine_tune;
static adlinsdata2 from_adldata(const adlinsdata &d);
};
ADLDATA_BYTE_COMPARABLE(struct adlinsdata2)
#undef ADLDATA_BYTE_COMPARABLE
#pragma pack(pop)
/**
* @brief Bank global setup
*/
struct AdlBankSetup
{
int volumeModel;
bool deepTremolo;
bool deepVibrato;
bool adLibPercussions;
bool scaleModulators;
};
#ifndef DISABLE_EMBEDDED_BANKS
int maxAdlBanks();
extern const adldata adl[];
extern const adlinsdata adlins[];
extern const unsigned short banks[][256];
extern const char* const banknames[];
extern const AdlBankSetup adlbanksetup[];
#endif
/**
* @brief Conversion of storage formats
*/
inline adlinsdata2 adlinsdata2::from_adldata(const adlinsdata &d)
{
adlinsdata2 ins;
ins.tone = d.tone;
ins.flags = d.flags;
ins.ms_sound_kon = d.ms_sound_kon;
ins.ms_sound_koff = d.ms_sound_koff;
ins.midi_velocity_offset = d.midi_velocity_offset;
ins.voice2_fine_tune = d.voice2_fine_tune;
#ifdef DISABLE_EMBEDDED_BANKS
std::memset(ins.adl, 0, sizeof(adldata) * 2);
#else
ins.adl[0] = ::adl[d.adlno1];
ins.adl[1] = ::adl[d.adlno2];
#endif
return ins;
}
/**
* @brief Convert external instrument to internal instrument
*/
void cvt_ADLI_to_FMIns(adlinsdata2 &dst, const struct ADL_Instrument &src);
/**
* @brief Convert internal instrument to external instrument
*/
void cvt_FMIns_to_ADLI(struct ADL_Instrument &dst, const adlinsdata2 &src);
#endif //ADLDATA_H

View File

@ -1,54 +0,0 @@
/*
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ADLMIDI_HPP
#define ADLMIDI_HPP
#include "adlmidi.h"
struct ADL_MIDIPlayer;
class ADLMIDI_DECLSPEC AdlInstrumentTester
{
struct Impl;
Impl *P;
public:
explicit AdlInstrumentTester(ADL_MIDIPlayer *device);
virtual ~AdlInstrumentTester();
// Find list of adlib instruments that supposedly implement this GM
void FindAdlList();
void Touch(unsigned c, unsigned volume);
void DoNote(int note);
void NextGM(int offset);
void NextAdl(int offset);
bool HandleInputChar(char ch);
private:
AdlInstrumentTester(const AdlInstrumentTester &);
AdlInstrumentTester &operator=(const AdlInstrumentTester &);
};
#endif //ADLMIDI_HPP

View File

@ -1,127 +0,0 @@
/*
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ADLMIDI_BANKMAP_H
#define ADLMIDI_BANKMAP_H
#include <list>
#include <utility>
#include <stdint.h>
#include <stddef.h>
#include "adlmidi_ptr.hpp"
/**
* A simple hash map which accepts bank numbers as keys, can be reserved to a
* fixed size, offers O(1) search and insertion, has a hash function to
* optimize for the worst case, and has some good cache locality properties.
*/
template <class T>
class BasicBankMap
{
public:
typedef size_t key_type; /* the bank identifier */
typedef T mapped_type;
typedef std::pair<key_type, T> value_type;
BasicBankMap();
void reserve(size_t capacity);
size_t size() const
{ return m_size; }
size_t capacity() const
{ return m_capacity; }
bool empty() const
{ return m_size == 0; }
class iterator;
iterator begin() const;
iterator end() const;
struct do_not_expand_t {};
iterator find(key_type key);
void erase(iterator it);
std::pair<iterator, bool> insert(const value_type &value);
std::pair<iterator, bool> insert(const value_type &value, do_not_expand_t);
void clear();
T &operator[](key_type key);
private:
struct Slot;
enum { minimum_allocation = 4 };
enum
{
hash_bits = 8, /* worst case # of collisions: 128^2/2^hash_bits */
hash_buckets = 1 << hash_bits
};
public:
class iterator
{
public:
iterator();
value_type &operator*() const { return slot->value; }
value_type *operator->() const { return &slot->value; }
iterator &operator++();
bool operator==(const iterator &o) const;
bool operator!=(const iterator &o) const;
void to_ptrs(void *ptrs[3]);
static iterator from_ptrs(void *const ptrs[3]);
private:
Slot **buckets;
Slot *slot;
size_t index;
iterator(Slot **buckets, Slot *slot, size_t index);
#ifdef _MSC_VER
template<class _T>
friend class BasicBankMap;
#else
friend class BasicBankMap<T>;
#endif
};
private:
struct Slot {
Slot *next, *prev;
value_type value;
Slot() : next(NULL), prev(NULL) {}
};
AdlMIDI_SPtrArray<Slot *> m_buckets;
std::list< AdlMIDI_SPtrArray<Slot> > m_allocations;
Slot *m_freeslots;
size_t m_size;
size_t m_capacity;
static size_t hash(key_type key);
Slot *allocate_slot();
Slot *ensure_allocate_slot();
void free_slot(Slot *slot);
Slot *bucket_find(size_t index, key_type key);
void bucket_add(size_t index, Slot *slot);
void bucket_remove(size_t index, Slot *slot);
};
#include "adlmidi_bankmap.tcc"
#endif // ADLMIDI_BANKMAP_H

View File

@ -1,283 +0,0 @@
/*
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "adlmidi_bankmap.h"
#include <cassert>
template <class T>
inline BasicBankMap<T>::BasicBankMap()
: m_freeslots(NULL),
m_size(0),
m_capacity(0)
{
m_buckets.reset(new Slot *[hash_buckets]());
}
template <class T>
inline size_t BasicBankMap<T>::hash(key_type key)
{
// disregard the 0 high bit in LSB
key = key_type(key & 127) | key_type((key >> 8) << 7);
// take low part as hash value
return key & (hash_buckets - 1);
}
template <class T>
void BasicBankMap<T>::reserve(size_t capacity)
{
if(m_capacity >= capacity)
return;
size_t need = capacity - m_capacity;
const size_t minalloc = static_cast<size_t>(minimum_allocation);
need = (need < minalloc) ? minalloc : need;
AdlMIDI_SPtrArray<Slot> slotz;
slotz.reset(new Slot[need]);
m_allocations.push_back(slotz);
m_capacity += need;
for(size_t i = need; i-- > 0;)
free_slot(&slotz[i]);
}
template <class T>
typename BasicBankMap<T>::iterator
BasicBankMap<T>::begin() const
{
iterator it(m_buckets.get(), NULL, 0);
while(it.index < hash_buckets && !(it.slot = m_buckets[it.index]))
++it.index;
return it;
}
template <class T>
typename BasicBankMap<T>::iterator
BasicBankMap<T>::end() const
{
iterator it(m_buckets.get(), NULL, hash_buckets);
return it;
}
template <class T>
typename BasicBankMap<T>::iterator BasicBankMap<T>::find(key_type key)
{
size_t index = hash(key);
Slot *slot = bucket_find(index, key);
if(!slot)
return end();
return iterator(m_buckets.get(), slot, index);
}
template <class T>
void BasicBankMap<T>::erase(iterator it)
{
bucket_remove(it.index, it.slot);
free_slot(it.slot);
--m_size;
}
template <class T>
inline BasicBankMap<T>::iterator::iterator()
: buckets(NULL), slot(NULL), index(0)
{
}
template <class T>
inline BasicBankMap<T>::iterator::iterator(Slot **buckets, Slot *slot, size_t index)
: buckets(buckets), slot(slot), index(index)
{
}
template <class T>
typename BasicBankMap<T>::iterator &
BasicBankMap<T>::iterator::operator++()
{
if(slot->next)
slot = slot->next;
else {
Slot *slot = NULL;
++index;
while(index < hash_buckets && !(slot = buckets[index]))
++index;
this->slot = slot;
}
return *this;
}
template <class T>
bool BasicBankMap<T>::iterator::operator==(const iterator &o) const
{
return buckets == o.buckets && slot == o.slot && index == o.index;
}
template <class T>
inline bool BasicBankMap<T>::iterator::operator!=(const iterator &o) const
{
return !operator==(o);
}
template <class T>
void BasicBankMap<T>::iterator::to_ptrs(void *ptrs[3])
{
ptrs[0] = buckets;
ptrs[1] = slot;
ptrs[2] = (void *)index;
}
template <class T>
typename BasicBankMap<T>::iterator
BasicBankMap<T>::iterator::from_ptrs(void *const ptrs[3])
{
iterator it;
it.buckets = (Slot **)ptrs[0];
it.slot = (Slot *)ptrs[1];
it.index = (size_t)ptrs[2];
return it;
}
template <class T>
std::pair<typename BasicBankMap<T>::iterator, bool>
BasicBankMap<T>::insert(const value_type &value)
{
size_t index = hash(value.first);
Slot *slot = bucket_find(index, value.first);
if(slot)
return std::make_pair(iterator(m_buckets.get(), slot, index), false);
slot = allocate_slot();
if(!slot) {
reserve(m_capacity + minimum_allocation);
slot = ensure_allocate_slot();
}
slot->value = value;
bucket_add(index, slot);
++m_size;
return std::make_pair(iterator(m_buckets.get(), slot, index), true);
}
template <class T>
std::pair<typename BasicBankMap<T>::iterator, bool>
BasicBankMap<T>::insert(const value_type &value, do_not_expand_t)
{
size_t index = hash(value.first);
Slot *slot = bucket_find(index, value.first);
if(slot)
return std::make_pair(iterator(m_buckets.get(), slot, index), false);
slot = allocate_slot();
if(!slot)
return std::make_pair(end(), false);
slot->value = value;
bucket_add(index, slot);
++m_size;
return std::make_pair(iterator(m_buckets.get(), slot, index), true);
}
template <class T>
void BasicBankMap<T>::clear()
{
for(size_t i = 0; i < hash_buckets; ++i) {
Slot *slot = m_buckets[i];
while (Slot *cur = slot) {
slot = slot->next;
free_slot(cur);
}
m_buckets[i] = NULL;
}
m_size = 0;
}
template <class T>
inline T &BasicBankMap<T>::operator[](key_type key)
{
return insert(value_type(key, T())).first->second;
}
template <class T>
typename BasicBankMap<T>::Slot *
BasicBankMap<T>::allocate_slot()
{
Slot *slot = m_freeslots;
if(!slot)
return NULL;
Slot *next = slot->next;
if(next)
next->prev = NULL;
m_freeslots = next;
return slot;
}
template <class T>
inline typename BasicBankMap<T>::Slot *
BasicBankMap<T>::ensure_allocate_slot()
{
Slot *slot = allocate_slot();
assert(slot);
return slot;
}
template <class T>
void BasicBankMap<T>::free_slot(Slot *slot)
{
Slot *next = m_freeslots;
if(next)
next->prev = slot;
slot->prev = NULL;
slot->next = next;
m_freeslots = slot;
m_freeslots->value.second = T();
}
template <class T>
typename BasicBankMap<T>::Slot *
BasicBankMap<T>::bucket_find(size_t index, key_type key)
{
Slot *slot = m_buckets[index];
while(slot && slot->value.first != key)
slot = slot->next;
return slot;
}
template <class T>
void BasicBankMap<T>::bucket_add(size_t index, Slot *slot)
{
assert(slot);
Slot *next = m_buckets[index];
if(next)
next->prev = slot;
slot->next = next;
m_buckets[index] = slot;
}
template <class T>
void BasicBankMap<T>::bucket_remove(size_t index, Slot *slot)
{
assert(slot);
Slot *prev = slot->prev;
Slot *next = slot->next;
if(!prev)
m_buckets[index] = next;
else
prev->next = next;
if(next)
next->prev = prev;
}

View File

@ -1,124 +0,0 @@
/*
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "adldata.hh"
#include "wopl/wopl_file.h"
#include <cmath>
template <class WOPLI>
static void cvt_generic_to_FMIns(adlinsdata2 &ins, const WOPLI &in)
{
ins.voice2_fine_tune = 0.0;
int8_t voice2_fine_tune = in.second_voice_detune;
if(voice2_fine_tune != 0)
{
if(voice2_fine_tune == 1)
ins.voice2_fine_tune = 0.000025;
else if(voice2_fine_tune == -1)
ins.voice2_fine_tune = -0.000025;
else
ins.voice2_fine_tune = voice2_fine_tune * (15.625 / 1000.0);
}
ins.midi_velocity_offset = in.midi_velocity_offset;
ins.tone = in.percussion_key_number;
ins.flags = (in.inst_flags & WOPL_Ins_4op) && (in.inst_flags & WOPL_Ins_Pseudo4op) ? adlinsdata::Flag_Pseudo4op : 0;
ins.flags|= (in.inst_flags & WOPL_Ins_4op) && ((in.inst_flags & WOPL_Ins_Pseudo4op) == 0) ? adlinsdata::Flag_Real4op : 0;
ins.flags|= (in.inst_flags & WOPL_Ins_IsBlank) ? adlinsdata::Flag_NoSound : 0;
ins.flags|= in.inst_flags & WOPL_RhythmModeMask;
for(size_t op = 0, slt = 0; op < 4; op++, slt++)
{
ins.adl[slt].carrier_E862 =
((static_cast<uint32_t>(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm
| ((static_cast<uint32_t>(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel
| ((static_cast<uint32_t>(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec
| ((static_cast<uint32_t>(in.operators[op].avekf_20) << 0) & 0x000000FF); //AVEKM
ins.adl[slt].carrier_40 = in.operators[op].ksl_l_40;//KSLL
op++;
ins.adl[slt].modulator_E862 =
((static_cast<uint32_t>(in.operators[op].waveform_E0) << 24) & 0xFF000000) //WaveForm
| ((static_cast<uint32_t>(in.operators[op].susrel_80) << 16) & 0x00FF0000) //SusRel
| ((static_cast<uint32_t>(in.operators[op].atdec_60) << 8) & 0x0000FF00) //AtDec
| ((static_cast<uint32_t>(in.operators[op].avekf_20) << 0) & 0x000000FF); //AVEKM
ins.adl[slt].modulator_40 = in.operators[op].ksl_l_40;//KSLL
}
ins.adl[0].finetune = static_cast<int8_t>(in.note_offset1);
ins.adl[0].feedconn = in.fb_conn1_C0;
ins.adl[1].finetune = static_cast<int8_t>(in.note_offset2);
ins.adl[1].feedconn = in.fb_conn2_C0;
ins.ms_sound_kon = in.delay_on_ms;
ins.ms_sound_koff = in.delay_off_ms;
}
template <class WOPLI>
static void cvt_FMIns_to_generic(WOPLI &ins, const adlinsdata2 &in)
{
ins.second_voice_detune = 0;
double voice2_fine_tune = in.voice2_fine_tune;
if(voice2_fine_tune != 0)
{
if(voice2_fine_tune > 0 && voice2_fine_tune <= 0.000025)
ins.second_voice_detune = 1;
else if(voice2_fine_tune < 0 && voice2_fine_tune >= -0.000025)
ins.second_voice_detune = -1;
else
{
long value = static_cast<long>(round(voice2_fine_tune * (1000.0 / 15.625)));
value = (value < -128) ? -128 : value;
value = (value > +127) ? +127 : value;
ins.second_voice_detune = static_cast<int8_t>(value);
}
}
ins.midi_velocity_offset = in.midi_velocity_offset;
ins.percussion_key_number = in.tone;
ins.inst_flags = (in.flags & (adlinsdata::Flag_Pseudo4op|adlinsdata::Flag_Real4op)) ? WOPL_Ins_4op : 0;
ins.inst_flags|= (in.flags & adlinsdata::Flag_Pseudo4op) ? WOPL_Ins_Pseudo4op : 0;
ins.inst_flags|= (in.flags & adlinsdata::Flag_NoSound) ? WOPL_Ins_IsBlank : 0;
ins.inst_flags |= in.flags & adlinsdata::Mask_RhythmMode;
for(size_t op = 0; op < 4; op++)
{
const adldata &in2op = in.adl[(op < 2) ? 0 : 1];
uint32_t regE862 = ((op & 1) == 0) ? in2op.carrier_E862 : in2op.modulator_E862;
uint8_t reg40 = ((op & 1) == 0) ? in2op.carrier_40 : in2op.modulator_40;
ins.operators[op].waveform_E0 = static_cast<uint8_t>(regE862 >> 24);
ins.operators[op].susrel_80 = static_cast<uint8_t>(regE862 >> 16);
ins.operators[op].atdec_60 = static_cast<uint8_t>(regE862 >> 8);
ins.operators[op].avekf_20 = static_cast<uint8_t>(regE862 >> 0);
ins.operators[op].ksl_l_40 = reg40;
}
ins.note_offset1 = in.adl[0].finetune;
ins.fb_conn1_C0 = in.adl[0].feedconn;
ins.note_offset2 = in.adl[1].finetune;
ins.fb_conn2_C0 = in.adl[1].feedconn;
ins.delay_on_ms = in.ms_sound_kon;
ins.delay_off_ms = in.ms_sound_koff;
}

View File

@ -1,287 +0,0 @@
/*
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "adlmidi_private.hpp"
#include "adlmidi_cvt.hpp"
#include "wopl/wopl_file.h"
bool MIDIplay::LoadBank(const std::string &filename)
{
FileAndMemReader file;
file.openFile(filename.c_str());
return LoadBank(file);
}
bool MIDIplay::LoadBank(const void *data, size_t size)
{
FileAndMemReader file;
file.openData(data, size);
return LoadBank(file);
}
void cvt_ADLI_to_FMIns(adlinsdata2 &ins, const ADL_Instrument &in)
{
return cvt_generic_to_FMIns(ins, in);
}
void cvt_FMIns_to_ADLI(ADL_Instrument &ins, const adlinsdata2 &in)
{
cvt_FMIns_to_generic(ins, in);
}
bool MIDIplay::LoadBank(FileAndMemReader &fr)
{
int err = 0;
WOPLFile *wopl = NULL;
char *raw_file_data = NULL;
size_t fsize;
if(!fr.isValid())
{
errorStringOut = "Custom bank: Invalid data stream!";
return false;
}
// Read complete bank file into the memory
fsize = fr.fileSize();
fr.seek(0, FileAndMemReader::SET);
// Allocate necessary memory block
raw_file_data = (char*)malloc(fsize);
if(!raw_file_data)
{
errorStringOut = "Custom bank: Out of memory before of read!";
return false;
}
fr.read(raw_file_data, 1, fsize);
// Parse bank file from the memory
wopl = WOPL_LoadBankFromMem((void*)raw_file_data, fsize, &err);
//Free the buffer no more needed
free(raw_file_data);
// Check for any erros
if(!wopl)
{
switch(err)
{
case WOPL_ERR_BAD_MAGIC:
errorStringOut = "Custom bank: Invalid magic!";
return false;
case WOPL_ERR_UNEXPECTED_ENDING:
errorStringOut = "Custom bank: Unexpected ending!";
return false;
case WOPL_ERR_INVALID_BANKS_COUNT:
errorStringOut = "Custom bank: Invalid banks count!";
return false;
case WOPL_ERR_NEWER_VERSION:
errorStringOut = "Custom bank: Version is newer than supported by this library!";
return false;
case WOPL_ERR_OUT_OF_MEMORY:
errorStringOut = "Custom bank: Out of memory!";
return false;
default:
errorStringOut = "Custom bank: Unknown error!";
return false;
}
}
m_synth.m_insBankSetup.adLibPercussions = false;
m_synth.m_insBankSetup.scaleModulators = false;
m_synth.m_insBankSetup.deepTremolo = (wopl->opl_flags & WOPL_FLAG_DEEP_TREMOLO) != 0;
m_synth.m_insBankSetup.deepVibrato = (wopl->opl_flags & WOPL_FLAG_DEEP_VIBRATO) != 0;
m_synth.m_insBankSetup.volumeModel = wopl->volume_model;
m_setup.deepTremoloMode = -1;
m_setup.deepVibratoMode = -1;
m_setup.volumeScaleModel = ADLMIDI_VolumeModel_AUTO;
m_synth.setEmbeddedBank(m_setup.bankId);
uint16_t slots_counts[2] = {wopl->banks_count_melodic, wopl->banks_count_percussion};
WOPLBank *slots_src_ins[2] = { wopl->banks_melodic, wopl->banks_percussive };
for(size_t ss = 0; ss < 2; ss++)
{
for(size_t i = 0; i < slots_counts[ss]; i++)
{
size_t bankno = (slots_src_ins[ss][i].bank_midi_msb * 256) +
(slots_src_ins[ss][i].bank_midi_lsb) +
(ss ? size_t(OPL3::PercussionTag) : 0);
OPL3::Bank &bank = m_synth.m_insBanks[bankno];
for(int j = 0; j < 128; j++)
{
adlinsdata2 &ins = bank.ins[j];
std::memset(&ins, 0, sizeof(adlinsdata2));
WOPLInstrument &inIns = slots_src_ins[ss][i].ins[j];
cvt_generic_to_FMIns(ins, inIns);
}
}
}
m_synth.m_embeddedBank = OPL3::CustomBankTag; // Use dynamic banks!
//Percussion offset is count of instruments multipled to count of melodic banks
applySetup();
WOPL_Free(wopl);
return true;
}
#ifndef ADLMIDI_DISABLE_MIDI_SEQUENCER
bool MIDIplay::LoadMIDI_pre()
{
#ifdef DISABLE_EMBEDDED_BANKS
if((m_synth.m_embeddedBank != OPL3::CustomBankTag) || m_synth.m_insBanks.empty())
{
errorStringOut = "Bank is not set! Please load any instruments bank by using of adl_openBankFile() or adl_openBankData() functions!";
return false;
}
#endif
/**** Set all properties BEFORE starting of actial file reading! ****/
resetMIDI();
applySetup();
return true;
}
bool MIDIplay::LoadMIDI_post()
{
MidiSequencer::FileFormat format = m_sequencer.getFormat();
if(format == MidiSequencer::Format_CMF)
{
const std::vector<MidiSequencer::CmfInstrument> &instruments = m_sequencer.getRawCmfInstruments();
m_synth.m_insBanks.clear();//Clean up old banks
uint16_t ins_count = static_cast<uint16_t>(instruments.size());
for(uint16_t i = 0; i < ins_count; ++i)
{
const uint8_t *InsData = instruments[i].data;
size_t bank = i / 256;
bank = ((bank & 127) + ((bank >> 7) << 8));
if(bank > 127 + (127 << 8))
break;
bank += (i % 256 < 128) ? 0 : size_t(OPL3::PercussionTag);
/*std::printf("Ins %3u: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
i, InsData[0],InsData[1],InsData[2],InsData[3], InsData[4],InsData[5],InsData[6],InsData[7],
InsData[8],InsData[9],InsData[10],InsData[11], InsData[12],InsData[13],InsData[14],InsData[15]);*/
adlinsdata2 &adlins = m_synth.m_insBanks[bank].ins[i % 128];
adldata adl;
adl.modulator_E862 =
((static_cast<uint32_t>(InsData[8] & 0x07) << 24) & 0xFF000000) //WaveForm
| ((static_cast<uint32_t>(InsData[6]) << 16) & 0x00FF0000) //Sustain/Release
| ((static_cast<uint32_t>(InsData[4]) << 8) & 0x0000FF00) //Attack/Decay
| ((static_cast<uint32_t>(InsData[0]) << 0) & 0x000000FF); //MultKEVA
adl.carrier_E862 =
((static_cast<uint32_t>(InsData[9] & 0x07) << 24) & 0xFF000000) //WaveForm
| ((static_cast<uint32_t>(InsData[7]) << 16) & 0x00FF0000) //Sustain/Release
| ((static_cast<uint32_t>(InsData[5]) << 8) & 0x0000FF00) //Attack/Decay
| ((static_cast<uint32_t>(InsData[1]) << 0) & 0x000000FF); //MultKEVA
adl.modulator_40 = InsData[2];
adl.carrier_40 = InsData[3];
adl.feedconn = InsData[10] & 0x0F;
adl.finetune = 0;
adlins.adl[0] = adl;
adlins.adl[1] = adl;
adlins.ms_sound_kon = 1000;
adlins.ms_sound_koff = 500;
adlins.tone = 0;
adlins.flags = 0;
adlins.voice2_fine_tune = 0.0;
}
m_synth.m_embeddedBank = OPL3::CustomBankTag; // Ignore AdlBank number, use dynamic banks instead
//std::printf("CMF deltas %u ticks %u, basictempo = %u\n", deltas, ticks, basictempo);
m_synth.m_rhythmMode = true;
m_synth.m_musicMode = OPL3::MODE_CMF;
m_synth.m_volumeScale = OPL3::VOLUME_NATIVE;
m_synth.m_numChips = 1;
m_synth.m_numFourOps = 0;
}
else if(format == MidiSequencer::Format_RSXX)
{
//opl.CartoonersVolumes = true;
m_synth.m_musicMode = OPL3::MODE_RSXX;
m_synth.m_volumeScale = OPL3::VOLUME_NATIVE;
m_synth.m_numChips = 1;
m_synth.m_numFourOps = 0;
}
else if(format == MidiSequencer::Format_IMF)
{
//std::fprintf(stderr, "Done reading IMF file\n");
m_synth.m_numFourOps = 0; //Don't use 4-operator channels for IMF playing!
m_synth.m_musicMode = OPL3::MODE_IMF;
m_synth.m_numChips = 1;
m_synth.m_numFourOps = 0;
}
else
{
m_synth.m_numChips = m_setup.numChips;
if(m_setup.numFourOps < 0)
adlCalculateFourOpChannels(this, true);
}
m_setup.tick_skip_samples_delay = 0;
m_synth.reset(m_setup.emulator, m_setup.PCM_RATE, this); // Reset OPL3 chip
//opl.Reset(); // ...twice (just in case someone misprogrammed OPL3 previously)
m_chipChannels.clear();
m_chipChannels.resize(m_synth.m_numChannels);
return true;
}
bool MIDIplay::LoadMIDI(const std::string &filename)
{
FileAndMemReader file;
file.openFile(filename.c_str());
if(!LoadMIDI_pre())
return false;
if(!m_sequencer.loadMIDI(file))
{
errorStringOut = m_sequencer.getErrorString();
return false;
}
if(!LoadMIDI_post())
return false;
return true;
}
bool MIDIplay::LoadMIDI(const void *data, size_t size)
{
FileAndMemReader file;
file.openData(data, size);
if(!LoadMIDI_pre())
return false;
if(!m_sequencer.loadMIDI(file))
{
errorStringOut = m_sequencer.getErrorString();
return false;
}
if(!LoadMIDI_post())
return false;
return true;
}
#endif /* ADLMIDI_DISABLE_MIDI_SEQUENCER */

View File

@ -1,753 +0,0 @@
/*
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "adlmidi_private.hpp"
#include <stdlib.h>
#include <cassert>
#ifdef ADLMIDI_HW_OPL
static const unsigned OPLBase = 0x388;
#else
# if defined(ADLMIDI_DISABLE_NUKED_EMULATOR) && defined(ADLMIDI_DISABLE_DOSBOX_EMULATOR)
# error "No emulators enabled. You must enable at least one emulator to use this library!"
# endif
// Nuked OPL3 emulator, Most accurate, but requires the powerful CPU
# ifndef ADLMIDI_DISABLE_NUKED_EMULATOR
# include "chips/nuked_opl3.h"
# include "chips/nuked_opl3_v174.h"
# endif
// DosBox 0.74 OPL3 emulator, Well-accurate and fast
# ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR
# include "chips/dosbox_opl3.h"
# endif
#endif
static const unsigned adl_emulatorSupport = 0
#ifndef ADLMIDI_HW_OPL
# ifndef ADLMIDI_DISABLE_NUKED_EMULATOR
| (1u << ADLMIDI_EMU_NUKED) | (1u << ADLMIDI_EMU_NUKED_174)
# endif
# ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR
| (1u << ADLMIDI_EMU_DOSBOX)
# endif
#endif
;
//! Check emulator availability
bool adl_isEmulatorAvailable(int emulator)
{
return (adl_emulatorSupport & (1u << (unsigned)emulator)) != 0;
}
//! Find highest emulator
int adl_getHighestEmulator()
{
int emu = -1;
for(unsigned m = adl_emulatorSupport; m > 0; m >>= 1)
++emu;
return emu;
}
//! Find lowest emulator
int adl_getLowestEmulator()
{
int emu = -1;
unsigned m = adl_emulatorSupport;
if(m > 0)
{
for(emu = 0; (m & 1) == 0; m >>= 1)
++emu;
}
return emu;
}
//! Per-channel and per-operator registers map
static const uint16_t g_operatorsMap[23 * 2] =
{
// Channels 0-2
0x000, 0x003, 0x001, 0x004, 0x002, 0x005, // operators 0, 3, 1, 4, 2, 5
// Channels 3-5
0x008, 0x00B, 0x009, 0x00C, 0x00A, 0x00D, // operators 6, 9, 7,10, 8,11
// Channels 6-8
0x010, 0x013, 0x011, 0x014, 0x012, 0x015, // operators 12,15, 13,16, 14,17
// Same for second card
0x100, 0x103, 0x101, 0x104, 0x102, 0x105, // operators 18,21, 19,22, 20,23
0x108, 0x10B, 0x109, 0x10C, 0x10A, 0x10D, // operators 24,27, 25,28, 26,29
0x110, 0x113, 0x111, 0x114, 0x112, 0x115, // operators 30,33, 31,34, 32,35
// Channel 18
0x010, 0x013, // operators 12,15
// Channel 19
0x014, 0xFFF, // operator 16
// Channel 19
0x012, 0xFFF, // operator 14
// Channel 19
0x015, 0xFFF, // operator 17
// Channel 19
0x011, 0xFFF
}; // operator 13
//! Channel map to regoster offsets
static const uint16_t g_channelsMap[23] =
{
0x000, 0x001, 0x002, 0x003, 0x004, 0x005, 0x006, 0x007, 0x008, // 0..8
0x100, 0x101, 0x102, 0x103, 0x104, 0x105, 0x106, 0x107, 0x108, // 9..17 (secondary set)
0x006, 0x007, 0x008, 0xFFF, 0xFFF
}; // <- hw percussions, 0xFFF = no support for pitch/pan
/*
In OPL3 mode:
0 1 2 6 7 8 9 10 11 16 17 18
op0 op1 op2 op12 op13 op14 op18 op19 op20 op30 op31 op32
op3 op4 op5 op15 op16 op17 op21 op22 op23 op33 op34 op35
3 4 5 13 14 15
op6 op7 op8 op24 op25 op26
op9 op10 op11 op27 op28 op29
Ports:
+0 +1 +2 +10 +11 +12 +100 +101 +102 +110 +111 +112
+3 +4 +5 +13 +14 +15 +103 +104 +105 +113 +114 +115
+8 +9 +A +108 +109 +10A
+B +C +D +10B +10C +10D
Percussion:
bassdrum = op(0): 0xBD bit 0x10, operators 12 (0x10) and 15 (0x13) / channels 6, 6b
snare = op(3): 0xBD bit 0x08, operators 16 (0x14) / channels 7b
tomtom = op(4): 0xBD bit 0x04, operators 14 (0x12) / channels 8
cym = op(5): 0xBD bit 0x02, operators 17 (0x17) / channels 8b
hihat = op(2): 0xBD bit 0x01, operators 13 (0x11) / channels 7
In OPTi mode ("extended FM" in 82C924, 82C925, 82C931 chips):
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
op0 op4 op6 op10 op12 op16 op18 op22 op24 op28 op30 op34 op36 op38 op40 op42 op44 op46
op1 op5 op7 op11 op13 op17 op19 op23 op25 op29 op31 op35 op37 op39 op41 op43 op45 op47
op2 op8 op14 op20 op26 op32
op3 op9 op15 op21 op27 op33 for a total of 6 quad + 12 dual
Ports: ???
*/
static adlinsdata2 makeEmptyInstrument()
{
adlinsdata2 ins;
memset(&ins, 0, sizeof(adlinsdata2));
ins.flags = adlinsdata::Flag_NoSound;
return ins;
}
const adlinsdata2 OPL3::m_emptyInstrument = makeEmptyInstrument();
OPL3::OPL3() :
m_numChips(1),
m_numFourOps(0),
m_deepTremoloMode(false),
m_deepVibratoMode(false),
m_rhythmMode(false),
m_softPanning(false),
m_musicMode(MODE_MIDI),
m_volumeScale(VOLUME_Generic)
{
m_insBankSetup.volumeModel = OPL3::VOLUME_Generic;
m_insBankSetup.deepTremolo = false;
m_insBankSetup.deepVibrato = false;
m_insBankSetup.adLibPercussions = false;
m_insBankSetup.scaleModulators = false;
#ifdef DISABLE_EMBEDDED_BANKS
m_embeddedBank = CustomBankTag;
#else
setEmbeddedBank(0);
#endif
}
bool OPL3::setupLocked()
{
return (m_musicMode == MODE_CMF ||
m_musicMode == MODE_IMF ||
m_musicMode == MODE_RSXX);
}
void OPL3::setEmbeddedBank(uint32_t bank)
{
#ifndef DISABLE_EMBEDDED_BANKS
m_embeddedBank = bank;
//Embedded banks are supports 128:128 GM set only
m_insBanks.clear();
if(bank >= static_cast<unsigned int>(maxAdlBanks()))
return;
Bank *bank_pair[2] =
{
&m_insBanks[0],
&m_insBanks[PercussionTag]
};
for(unsigned i = 0; i < 256; ++i)
{
size_t meta = banks[bank][i];
adlinsdata2 &ins = bank_pair[i / 128]->ins[i % 128];
ins = adlinsdata2::from_adldata(::adlins[meta]);
}
#else
ADL_UNUSED(bank);
#endif
}
void OPL3::writeReg(size_t chip, uint16_t address, uint8_t value)
{
#ifdef ADLMIDI_HW_OPL
ADL_UNUSED(chip);
unsigned o = address >> 8;
unsigned port = OPLBase + o * 2;
#ifdef __DJGPP__
outportb(port, address);
for(unsigned c = 0; c < 6; ++c) inportb(port);
outportb(port + 1, value);
for(unsigned c = 0; c < 35; ++c) inportb(port);
#endif
#ifdef __WATCOMC__
outp(port, address);
for(uint16_t c = 0; c < 6; ++c) inp(port);
outp(port + 1, value);
for(uint16_t c = 0; c < 35; ++c) inp(port);
#endif//__WATCOMC__
#else//ADLMIDI_HW_OPL
m_chips[chip]->writeReg(address, value);
#endif
}
void OPL3::writeRegI(size_t chip, uint32_t address, uint32_t value)
{
#ifdef ADLMIDI_HW_OPL
writeReg(chip, static_cast<uint16_t>(address), static_cast<uint8_t>(value));
#else//ADLMIDI_HW_OPL
m_chips[chip]->writeReg(static_cast<uint16_t>(address), static_cast<uint8_t>(value));
#endif
}
void OPL3::writePan(size_t chip, uint32_t address, uint32_t value)
{
#ifndef ADLMIDI_HW_OPL
m_chips[chip]->writePan(static_cast<uint16_t>(address), static_cast<uint8_t>(value));
#else
ADL_UNUSED(chip);
ADL_UNUSED(address);
ADL_UNUSED(value);
#endif
}
void OPL3::noteOff(size_t c)
{
size_t chip = c / 23, cc = c % 23;
if(cc >= 18)
{
m_regBD[chip] &= ~(0x10 >> (cc - 18));
writeRegI(chip, 0xBD, m_regBD[chip]);
return;
}
writeRegI(chip, 0xB0 + g_channelsMap[cc], m_keyBlockFNumCache[c] & 0xDF);
}
void OPL3::noteOn(size_t c1, size_t c2, double hertz) // Hertz range: 0..131071
{
size_t chip = c1 / 23, cc1 = c1 % 23, cc2 = c2 % 23;
uint32_t octave = 0, ftone = 0, mul_offset = 0;
if(hertz < 0)
return;
//Basic range until max of octaves reaching
while((hertz >= 1023.5) && (octave < 0x1C00))
{
hertz /= 2.0; // Calculate octave
octave += 0x400;
}
//Extended range, rely on frequency multiplication increment
while(hertz >= 1022.75)
{
hertz /= 2.0; // Calculate octave
mul_offset++;
}
ftone = octave + static_cast<uint32_t>(hertz + 0.5);
uint32_t chn = g_channelsMap[cc1];
const adldata &patch1 = m_insCache[c1];
const adldata &patch2 = m_insCache[c2 < m_insCache.size() ? c2 : 0];
if(cc1 < 18)
{
ftone += 0x2000u; /* Key-ON [KON] */
const bool natural_4op = (m_channelCategory[c1] == ChanCat_4op_Master);
const size_t opsCount = natural_4op ? 4 : 2;
const uint16_t op_addr[4] =
{
g_operatorsMap[cc1 * 2 + 0], g_operatorsMap[cc1 * 2 + 1],
g_operatorsMap[cc2 * 2 + 0], g_operatorsMap[cc2 * 2 + 1]
};
const uint32_t ops[4] =
{
patch1.modulator_E862 & 0xFF,
patch1.carrier_E862 & 0xFF,
patch2.modulator_E862 & 0xFF,
patch2.carrier_E862 & 0xFF
};
for(size_t op = 0; op < opsCount; op++)
{
if((op > 0) && (op_addr[op] == 0xFFF))
break;
if(mul_offset > 0)
{
uint32_t dt = ops[op] & 0xF0;
uint32_t mul = ops[op] & 0x0F;
if((mul + mul_offset) > 0x0F)
{
mul_offset = 0;
mul = 0x0F;
}
writeRegI(chip, 0x20 + op_addr[op], (dt | (mul + mul_offset)) & 0xFF);
}
else
{
writeRegI(chip, 0x20 + op_addr[op], ops[op] & 0xFF);
}
}
}
if(chn != 0xFFF)
{
writeRegI(chip , 0xA0 + chn, (ftone & 0xFF));
writeRegI(chip , 0xB0 + chn, (ftone >> 8));
m_keyBlockFNumCache[c1] = (ftone >> 8);
}
if(cc1 >= 18)
{
m_regBD[chip ] |= (0x10 >> (cc1 - 18));
writeRegI(chip , 0x0BD, m_regBD[chip ]);
//x |= 0x800; // for test
}
}
void OPL3::touchNote(size_t c, uint8_t volume, uint8_t brightness)
{
if(volume > 63)
volume = 63;
size_t chip = c / 23, cc = c % 23;
const adldata &adli = m_insCache[c];
uint16_t o1 = g_operatorsMap[cc * 2 + 0];
uint16_t o2 = g_operatorsMap[cc * 2 + 1];
uint8_t x = adli.modulator_40, y = adli.carrier_40;
uint32_t mode = 1; // 2-op AM
if(m_channelCategory[c] == ChanCat_Regular ||
m_channelCategory[c] == ChanCat_Rhythm_Bass)
{
mode = adli.feedconn & 1; // 2-op FM or 2-op AM
}
else if(m_channelCategory[c] == ChanCat_4op_Master ||
m_channelCategory[c] == ChanCat_4op_Slave)
{
const adldata *i0, *i1;
if(m_channelCategory[c] == ChanCat_4op_Master)
{
i0 = &adli;
i1 = &m_insCache[c + 3];
mode = 2; // 4-op xx-xx ops 1&2
}
else
{
i0 = &m_insCache[c - 3];
i1 = &adli;
mode = 6; // 4-op xx-xx ops 3&4
}
mode += (i0->feedconn & 1) + (i1->feedconn & 1) * 2;
}
static const bool do_ops[10][2] =
{
{ false, true }, /* 2 op FM */
{ true, true }, /* 2 op AM */
{ false, false }, /* 4 op FM-FM ops 1&2 */
{ true, false }, /* 4 op AM-FM ops 1&2 */
{ false, true }, /* 4 op FM-AM ops 1&2 */
{ true, false }, /* 4 op AM-AM ops 1&2 */
{ false, true }, /* 4 op FM-FM ops 3&4 */
{ false, true }, /* 4 op AM-FM ops 3&4 */
{ false, true }, /* 4 op FM-AM ops 3&4 */
{ true, true } /* 4 op AM-AM ops 3&4 */
};
if(m_musicMode == MODE_RSXX)
{
writeRegI(chip, 0x40 + o1, x);
if(o2 != 0xFFF)
writeRegI(chip, 0x40 + o2, y - volume / 2);
}
else
{
bool do_modulator = do_ops[ mode ][ 0 ] || m_scaleModulators;
bool do_carrier = do_ops[ mode ][ 1 ] || m_scaleModulators;
uint32_t modulator = do_modulator ? (x | 63) - volume + volume * (x & 63) / 63 : x;
uint32_t carrier = do_carrier ? (y | 63) - volume + volume * (y & 63) / 63 : y;
if(brightness != 127)
{
brightness = static_cast<uint8_t>(::round(127.0 * ::sqrt((static_cast<double>(brightness)) * (1.0 / 127.0))) / 2.0);
if(!do_modulator)
modulator = (modulator | 63) - brightness + brightness * (modulator & 63) / 63;
if(!do_carrier)
carrier = (carrier | 63) - brightness + brightness * (carrier & 63) / 63;
}
writeRegI(chip, 0x40 + o1, modulator);
if(o2 != 0xFFF)
writeRegI(chip, 0x40 + o2, carrier);
}
// Correct formula (ST3, AdPlug):
// 63-((63-(instrvol))/63)*chanvol
// Reduces to (tested identical):
// 63 - chanvol + chanvol*instrvol/63
// Also (slower, floats):
// 63 + chanvol * (instrvol / 63.0 - 1)
}
/*
void OPL3::Touch(unsigned c, unsigned volume) // Volume maxes at 127*127*127
{
if(LogarithmicVolumes)
Touch_Real(c, volume * 127 / (127 * 127 * 127) / 2);
else
{
// The formula below: SOLVE(V=127^3 * 2^( (A-63.49999) / 8), A)
Touch_Real(c, volume > 8725 ? static_cast<unsigned int>(std::log(volume) * 11.541561 + (0.5 - 104.22845)) : 0);
// The incorrect formula below: SOLVE(V=127^3 * (2^(A/63)-1), A)
//Touch_Real(c, volume>11210 ? 91.61112 * std::log(4.8819E-7*volume + 1.0)+0.5 : 0);
}
}*/
void OPL3::setPatch(size_t c, const adldata &instrument)
{
size_t chip = c / 23, cc = c % 23;
static const uint8_t data[4] = {0x20, 0x60, 0x80, 0xE0};
m_insCache[c] = instrument;
uint16_t o1 = g_operatorsMap[cc * 2 + 0];
uint16_t o2 = g_operatorsMap[cc * 2 + 1];
unsigned x = instrument.modulator_E862, y = instrument.carrier_E862;
for(size_t a = 0; a < 4; ++a, x >>= 8, y >>= 8)
{
writeRegI(chip, data[a] + o1, x & 0xFF);
if(o2 != 0xFFF)
writeRegI(chip, data[a] + o2, y & 0xFF);
}
}
void OPL3::setPan(size_t c, uint8_t value)
{
size_t chip = c / 23, cc = c % 23;
if(g_channelsMap[cc] != 0xFFF)
{
#ifndef ADLMIDI_HW_OPL
if (m_softPanning)
{
writePan(chip, g_channelsMap[cc], value);
writeRegI(chip, 0xC0 + g_channelsMap[cc], m_insCache[c].feedconn | OPL_PANNING_BOTH);
}
else
{
#endif
int panning = 0;
if(value < 64 + 32) panning |= OPL_PANNING_LEFT;
if(value >= 64 - 32) panning |= OPL_PANNING_RIGHT;
writePan(chip, g_channelsMap[cc], 64);
writeRegI(chip, 0xC0 + g_channelsMap[cc], m_insCache[c].feedconn | panning);
#ifndef ADLMIDI_HW_OPL
}
#endif
}
}
void OPL3::silenceAll() // Silence all OPL channels.
{
for(size_t c = 0; c < m_numChannels; ++c)
{
noteOff(c);
touchNote(c, 0);
}
}
void OPL3::updateChannelCategories()
{
const uint32_t fours = m_numFourOps;
for(uint32_t chip = 0, fours_left = fours; chip < m_numChips; ++chip)
{
m_regBD[chip] = (m_deepTremoloMode * 0x80 + m_deepVibratoMode * 0x40 + m_rhythmMode * 0x20);
writeRegI(chip, 0x0BD, m_regBD[chip]);
uint32_t fours_this_chip = std::min(fours_left, static_cast<uint32_t>(6u));
writeRegI(chip, 0x104, (1 << fours_this_chip) - 1);
fours_left -= fours_this_chip;
}
if(!m_rhythmMode)
{
for(size_t a = 0, n = m_numChips; a < n; ++a)
{
for(size_t b = 0; b < 23; ++b)
{
m_channelCategory[a * 23 + b] =
(b >= 18) ? ChanCat_Rhythm_Slave : ChanCat_Regular;
}
}
}
else
{
for(size_t a = 0, n = m_numChips; a < n; ++a)
{
for(size_t b = 0; b < 23; ++b)
{
m_channelCategory[a * 23 + b] =
(b >= 18) ? static_cast<ChanCat>(ChanCat_Rhythm_Bass + (b - 18)) :
(b >= 6 && b < 9) ? ChanCat_Rhythm_Slave : ChanCat_Regular;
}
}
}
uint32_t nextfour = 0;
for(uint32_t a = 0; a < fours; ++a)
{
m_channelCategory[nextfour] = ChanCat_4op_Master;
m_channelCategory[nextfour + 3] = ChanCat_4op_Slave;
switch(a % 6)
{
case 0:
case 1:
nextfour += 1;
break;
case 2:
nextfour += 9 - 2;
break;
case 3:
case 4:
nextfour += 1;
break;
case 5:
nextfour += 23 - 9 - 2;
break;
}
}
/**/
/*
In two-op mode, channels 0..8 go as follows:
Op1[port] Op2[port]
Channel 0: 00 00 03 03
Channel 1: 01 01 04 04
Channel 2: 02 02 05 05
Channel 3: 06 08 09 0B
Channel 4: 07 09 10 0C
Channel 5: 08 0A 11 0D
Channel 6: 12 10 15 13
Channel 7: 13 11 16 14
Channel 8: 14 12 17 15
In four-op mode, channels 0..8 go as follows:
Op1[port] Op2[port] Op3[port] Op4[port]
Channel 0: 00 00 03 03 06 08 09 0B
Channel 1: 01 01 04 04 07 09 10 0C
Channel 2: 02 02 05 05 08 0A 11 0D
Channel 3: CHANNEL 0 SLAVE
Channel 4: CHANNEL 1 SLAVE
Channel 5: CHANNEL 2 SLAVE
Channel 6: 12 10 15 13
Channel 7: 13 11 16 14
Channel 8: 14 12 17 15
Same goes principally for channels 9-17 respectively.
*/
}
void OPL3::commitDeepFlags()
{
for(size_t chip = 0; chip < m_numChips; ++chip)
{
m_regBD[chip] = (m_deepTremoloMode * 0x80 + m_deepVibratoMode * 0x40 + m_rhythmMode * 0x20);
writeRegI(chip, 0x0BD, m_regBD[chip]);
}
}
void OPL3::setVolumeScaleModel(ADLMIDI_VolumeModels volumeModel)
{
switch(volumeModel)
{
case ADLMIDI_VolumeModel_AUTO://Do nothing until restart playing
break;
case ADLMIDI_VolumeModel_Generic:
m_volumeScale = OPL3::VOLUME_Generic;
break;
case ADLMIDI_VolumeModel_NativeOPL3:
m_volumeScale = OPL3::VOLUME_NATIVE;
break;
case ADLMIDI_VolumeModel_DMX:
m_volumeScale = OPL3::VOLUME_DMX;
break;
case ADLMIDI_VolumeModel_APOGEE:
m_volumeScale = OPL3::VOLUME_APOGEE;
break;
case ADLMIDI_VolumeModel_9X:
m_volumeScale = OPL3::VOLUME_9X;
break;
}
}
ADLMIDI_VolumeModels OPL3::getVolumeScaleModel()
{
switch(m_volumeScale)
{
default:
case OPL3::VOLUME_Generic:
return ADLMIDI_VolumeModel_Generic;
case OPL3::VOLUME_NATIVE:
return ADLMIDI_VolumeModel_NativeOPL3;
case OPL3::VOLUME_DMX:
return ADLMIDI_VolumeModel_DMX;
case OPL3::VOLUME_APOGEE:
return ADLMIDI_VolumeModel_APOGEE;
case OPL3::VOLUME_9X:
return ADLMIDI_VolumeModel_9X;
}
}
#ifndef ADLMIDI_HW_OPL
void OPL3::clearChips()
{
for(size_t i = 0; i < m_chips.size(); i++)
m_chips[i].reset(NULL);
m_chips.clear();
}
#endif
void OPL3::reset(int emulator, unsigned long PCM_RATE, void *audioTickHandler)
{
#ifndef ADLMIDI_HW_OPL
clearChips();
#else
(void)emulator;
(void)PCM_RATE;
#endif
#if !defined(ADLMIDI_AUDIO_TICK_HANDLER)
(void)audioTickHandler;
#endif
m_insCache.clear();
m_keyBlockFNumCache.clear();
m_regBD.clear();
#ifndef ADLMIDI_HW_OPL
m_chips.resize(m_numChips, AdlMIDI_SPtr<OPLChipBase>());
#endif
const struct adldata defaultInsCache = { 0x1557403,0x005B381, 0x49,0x80, 0x4, +0 };
m_numChannels = m_numChips * 23;
m_insCache.resize(m_numChannels, defaultInsCache);
m_keyBlockFNumCache.resize(m_numChannels, 0);
m_regBD.resize(m_numChips, 0);
m_channelCategory.resize(m_numChannels, 0);
for(size_t p = 0, a = 0; a < m_numChips; ++a)
{
for(size_t b = 0; b < 18; ++b)
m_channelCategory[p++] = 0;
for(size_t b = 0; b < 5; ++b)
m_channelCategory[p++] = ChanCat_Rhythm_Slave;
}
static const uint16_t data[] =
{
0x004, 96, 0x004, 128, // Pulse timer
0x105, 0, 0x105, 1, 0x105, 0, // Pulse OPL3 enable
0x001, 32, 0x105, 1 // Enable wave, OPL3 extensions
};
// size_t fours = m_numFourOps;
for(size_t i = 0; i < m_numChips; ++i)
{
#ifndef ADLMIDI_HW_OPL
OPLChipBase *chip;
switch(emulator)
{
default:
assert(false);
abort();
#ifndef ADLMIDI_DISABLE_NUKED_EMULATOR
case ADLMIDI_EMU_NUKED: /* Latest Nuked OPL3 */
chip = new NukedOPL3;
break;
case ADLMIDI_EMU_NUKED_174: /* Old Nuked OPL3 1.4.7 modified and optimized */
chip = new NukedOPL3v174;
break;
#endif
#ifndef ADLMIDI_DISABLE_DOSBOX_EMULATOR
case ADLMIDI_EMU_DOSBOX:
chip = new DosBoxOPL3;
break;
#endif
}
m_chips[i].reset(chip);
chip->setChipId((uint32_t)i);
chip->setRate((uint32_t)PCM_RATE);
if(m_runAtPcmRate)
chip->setRunningAtPcmRate(true);
# if defined(ADLMIDI_AUDIO_TICK_HANDLER)
chip->setAudioTickHandlerInstance(audioTickHandler);
# endif
#endif // ADLMIDI_HW_OPL
/* Clean-up channels from any playing junk sounds */
for(size_t a = 0; a < 18; ++a)
writeRegI(i, 0xB0 + g_channelsMap[a], 0x00);
for(size_t a = 0; a < sizeof(data) / sizeof(*data); a += 2)
writeRegI(i, data[a], (data[a + 1]));
}
updateChannelCategories();
silenceAll();
}

View File

@ -1,108 +0,0 @@
/*
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "adlmidi_private.hpp"
std::string ADLMIDI_ErrorString;
// Generator callback on audio rate ticks
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
void adl_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate)
{
reinterpret_cast<MIDIplay *>(instance)->AudioTick(chipId, rate);
}
#endif
int adlCalculateFourOpChannels(MIDIplay *play, bool silent)
{
size_t n_fourop[2] = {0, 0}, n_total[2] = {0, 0};
//Automatically calculate how much 4-operator channels is necessary
#ifndef DISABLE_EMBEDDED_BANKS
if(play->m_synth.m_embeddedBank == OPL3::CustomBankTag)
#endif
{
//For custom bank
OPL3::BankMap::iterator it = play->m_synth.m_insBanks.begin();
OPL3::BankMap::iterator end = play->m_synth.m_insBanks.end();
for(; it != end; ++it)
{
size_t bank = it->first;
size_t div = (bank & OPL3::PercussionTag) ? 1 : 0;
for(size_t i = 0; i < 128; ++i)
{
adlinsdata2 &ins = it->second.ins[i];
if(ins.flags & adlinsdata::Flag_NoSound)
continue;
if((ins.flags & adlinsdata::Flag_Real4op) != 0)
++n_fourop[div];
++n_total[div];
}
}
}
#ifndef DISABLE_EMBEDDED_BANKS
else
{
//For embedded bank
for(size_t a = 0; a < 256; ++a)
{
size_t insno = banks[play->m_setup.bankId][a];
if(insno == 198)
continue;
++n_total[a / 128];
adlinsdata2 ins = adlinsdata2::from_adldata(::adlins[insno]);
if((ins.flags & adlinsdata::Flag_Real4op) != 0)
++n_fourop[a / 128];
}
}
#endif
size_t numFourOps = 0;
// All 2ops (no 4ops)
if((n_fourop[0] == 0) && (n_fourop[1] == 0))
numFourOps = 0;
// All 2op melodics and Some (or All) 4op drums
else if((n_fourop[0] == 0) && (n_fourop[1] > 0))
numFourOps = 2;
// Many 4op melodics
else if((n_fourop[0] >= (n_total[0] * 7) / 8))
numFourOps = 6;
// Few 4op melodics
else if(n_fourop[0] > 0)
numFourOps = 4;
/* //Old formula
unsigned NumFourOps = ((n_fourop[0] == 0) && (n_fourop[1] == 0)) ? 0
: (n_fourop[0] >= (n_total[0] * 7) / 8) ? play->m_setup.NumCards * 6
: (play->m_setup.NumCards == 1 ? 1 : play->m_setup.NumCards * 4);
*/
play->m_synth.m_numFourOps = static_cast<unsigned>(numFourOps * play->m_synth.m_numChips);
// Update channel categories and set up four-operator channels
if(!silent)
play->m_synth.updateChannelCategories();
return 0;
}

View File

@ -1,217 +0,0 @@
/*
* libADLMIDI is a free MIDI to WAV conversion library with OPL3 emulation
*
* Original ADLMIDI code: Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
* ADLMIDI Library API: Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
*
* Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
* http://iki.fi/bisqwit/source/adlmidi.html
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef ADLMIDI_PTR_HPP_THING
#define ADLMIDI_PTR_HPP_THING
#include <algorithm> // swap
#include <stddef.h>
#include <stdlib.h>
/*
Generic deleters for smart pointers
*/
template <class T>
struct ADLMIDI_DefaultDelete
{
void operator()(T *x) { delete x; }
};
template <class T>
struct ADLMIDI_DefaultArrayDelete
{
void operator()(T *x) { delete[] x; }
};
struct ADLMIDI_CDelete
{
void operator()(void *x) { free(x); }
};
/*
Safe unique pointer for C++98, non-copyable but swappable.
*/
template< class T, class Deleter = ADLMIDI_DefaultDelete<T> >
class AdlMIDI_UPtr
{
T *m_p;
public:
explicit AdlMIDI_UPtr(T *p)
: m_p(p) {}
~AdlMIDI_UPtr()
{
reset();
}
void reset(T *p = NULL)
{
if(p != m_p) {
if(m_p) {
Deleter del;
del(m_p);
}
m_p = p;
}
}
void swap(AdlMIDI_UPtr &other)
{
std::swap(m_p, other.m_p);
}
T *get() const
{
return m_p;
}
T &operator*() const
{
return *m_p;
}
T *operator->() const
{
return m_p;
}
T &operator[](size_t index) const
{
return m_p[index];
}
private:
AdlMIDI_UPtr(const AdlMIDI_UPtr &);
AdlMIDI_UPtr &operator=(const AdlMIDI_UPtr &);
};
template <class T>
void swap(AdlMIDI_UPtr<T> &a, AdlMIDI_UPtr<T> &b)
{
a.swap(b);
}
/**
Unique pointer for arrays.
*/
template<class T>
class AdlMIDI_UPtrArray :
public AdlMIDI_UPtr< T, ADLMIDI_DefaultArrayDelete<T> >
{
public:
explicit AdlMIDI_UPtrArray(T *p = NULL)
: AdlMIDI_UPtr< T, ADLMIDI_DefaultArrayDelete<T> >(p) {}
};
/**
Unique pointer for C memory.
*/
template<class T>
class AdlMIDI_CPtr :
public AdlMIDI_UPtr< T, ADLMIDI_CDelete >
{
public:
explicit AdlMIDI_CPtr(T *p = NULL)
: AdlMIDI_UPtr< T, ADLMIDI_CDelete >(p) {}
};
/*
Shared pointer with non-atomic counter
FAQ: Why not std::shared_ptr? Because of Android NDK now doesn't supports it
*/
template< class T, class Deleter = ADLMIDI_DefaultDelete<T> >
class AdlMIDI_SPtr
{
T *m_p;
size_t *m_counter;
public:
explicit AdlMIDI_SPtr(T *p = NULL)
: m_p(p), m_counter(p ? new size_t(1) : NULL) {}
~AdlMIDI_SPtr()
{
reset(NULL);
}
AdlMIDI_SPtr(const AdlMIDI_SPtr &other)
: m_p(other.m_p), m_counter(other.m_counter)
{
if(m_counter)
++*m_counter;
}
AdlMIDI_SPtr &operator=(const AdlMIDI_SPtr &other)
{
if(this == &other)
return *this;
reset();
m_p = other.m_p;
m_counter = other.m_counter;
if(m_counter)
++*m_counter;
return *this;
}
void reset(T *p = NULL)
{
if(p != m_p) {
if(m_p && --*m_counter == 0) {
Deleter del;
del(m_p);
if(!p) {
delete m_counter;
m_counter = NULL;
}
}
m_p = p;
if(p) {
if(!m_counter)
m_counter = new size_t;
*m_counter = 1;
}
}
}
T *get() const
{
return m_p;
}
T &operator*() const
{
return *m_p;
}
T *operator->() const
{
return m_p;
}
T &operator[](size_t index) const
{
return m_p[index];
}
};
/**
Shared pointer for arrays.
*/
template<class T>
class AdlMIDI_SPtrArray :
public AdlMIDI_SPtr< T, ADLMIDI_DefaultArrayDelete<T> >
{
public:
explicit AdlMIDI_SPtrArray(T *p = NULL)
: AdlMIDI_SPtr< T, ADLMIDI_DefaultArrayDelete<T> >(p) {}
};
#endif //ADLMIDI_PTR_HPP_THING

View File

@ -1,290 +0,0 @@
/*
* Copyright (C) 2002-2018 The DOSBox Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <inttypes.h>
#include <stdint.h>
#include <sys/types.h>
#if defined(__GNUC__) && defined(__i386__)
#define DB_FASTCALL __attribute__((fastcall))
#elif defined(_MSC_VER)
#define DB_FASTCALL __fastcall
#else
#define DB_FASTCALL
#endif
typedef uintptr_t Bitu;
typedef intptr_t Bits;
typedef uint64_t Bit64u;
typedef int64_t Bit64s;
typedef uint32_t Bit32u;
typedef int32_t Bit32s;
typedef uint16_t Bit16u;
typedef int16_t Bit16s;
typedef uint8_t Bit8u;
typedef int8_t Bit8s;
//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume
#define WAVE_HANDLER 10
//Use a logarithmic wavetable with an exponential table for volume
#define WAVE_TABLELOG 11
//Use a linear wavetable with a multiply table for volume
#define WAVE_TABLEMUL 12
//Select the type of wave generator routine
#define DBOPL_WAVE WAVE_TABLEMUL
namespace DBOPL {
struct Chip;
struct Operator;
struct Channel;
#if (DBOPL_WAVE == WAVE_HANDLER)
typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume );
#endif
typedef Bits ( DBOPL::Operator::*VolumeHandler) ( );
typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output );
//Different synth modes that can generate blocks of data
typedef enum {
sm2AM,
sm2FM,
sm3AM,
sm3FM,
sm4Start,
sm3FMFM,
sm3AMFM,
sm3FMAM,
sm3AMAM,
sm6Start,
sm2Percussion,
sm3Percussion
} SynthMode;
//Shifts for the values contained in chandata variable
enum {
SHIFT_KSLBASE = 16,
SHIFT_KEYCODE = 24
};
struct Operator {
public:
//Masks for operator 20 values
enum {
MASK_KSR = 0x10,
MASK_SUSTAIN = 0x20,
MASK_VIBRATO = 0x40,
MASK_TREMOLO = 0x80
};
typedef enum {
OFF,
RELEASE,
SUSTAIN,
DECAY,
ATTACK
} State;
VolumeHandler volHandler;
#if (DBOPL_WAVE == WAVE_HANDLER)
WaveHandler waveHandler; //Routine that generate a wave
#else
Bit16s* waveBase;
Bit32u waveMask;
Bit32u waveStart;
#endif
Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index
Bit32u waveAdd; //The base frequency without vibrato
Bit32u waveCurrent; //waveAdd + vibratao
Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this
Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove?
Bit32u vibrato; //Scaled up vibrato strength
Bit32s sustainLevel; //When stopping at sustain level stop here
Bit32s totalLevel; //totalLevel is added to every generated volume
Bit32u currentLevel; //totalLevel + tremolo
Bit32s volume; //The currently active volume
Bit32u attackAdd; //Timers for the different states of the envelope
Bit32u decayAdd;
Bit32u releaseAdd;
Bit32u rateIndex; //Current position of the evenlope
Bit8u rateZero; //Bits for the different states of the envelope having no changes
Bit8u keyOn; //Bitmask of different values that can generate keyon
//Registers, also used to check for changes
Bit8u reg20, reg40, reg60, reg80, regE0;
//Active part of the envelope we're in
Bit8u state;
//0xff when tremolo is enabled
Bit8u tremoloMask;
//Strength of the vibrato
Bit8u vibStrength;
//Keep track of the calculated KSR so we can check for changes
Bit8u ksr;
private:
void SetState( Bit8u s );
void UpdateAttack( const Chip* chip );
void UpdateRelease( const Chip* chip );
void UpdateDecay( const Chip* chip );
public:
void UpdateAttenuation();
void UpdateRates( const Chip* chip );
void UpdateFrequency( );
void Write20( const Chip* chip, Bit8u val );
void Write40( const Chip* chip, Bit8u val );
void Write60( const Chip* chip, Bit8u val );
void Write80( const Chip* chip, Bit8u val );
void WriteE0( const Chip* chip, Bit8u val );
bool Silent() const;
void Prepare( const Chip* chip );
void KeyOn( Bit8u mask);
void KeyOff( Bit8u mask);
template< State state>
Bits TemplateVolume( );
Bit32s RateForward( Bit32u add );
Bitu ForwardWave();
Bitu ForwardVolume();
Bits GetSample( Bits modulation );
Bits GetWave( Bitu index, Bitu vol );
public:
Operator();
};
struct Channel {
Operator op[2];
inline Operator* Op( Bitu index ) {
return &( ( this + (index >> 1) )->op[ index & 1 ]);
}
SynthHandler synthHandler;
Bit32u chanData; //Frequency/octave and derived values
Bit32s old[2]; //Old data for feedback
Bit8u feedback; //Feedback shift
Bit8u regB0; //Register values to check for changes
Bit8u regC0;
//This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel
Bit8u fourMask;
Bit8s maskLeft; //Sign extended values for both channel's panning
Bit8s maskRight;
Bit16u panLeft; // Extended behavior, scale values for soft panning
Bit16u panRight;
//Forward the channel data to the operators of the channel
void SetChanData( const Chip* chip, Bit32u data );
//Change in the chandata, check for new values and if we have to forward to operators
void UpdateFrequency( const Chip* chip, Bit8u fourOp );
void UpdateSynth(const Chip* chip);
void WriteA0( const Chip* chip, Bit8u val );
void WriteB0( const Chip* chip, Bit8u val );
void WriteC0( const Chip* chip, Bit8u val );
void WritePan( Bit8u val );
//call this for the first channel
template< bool opl3Mode >
void GeneratePercussion( Chip* chip, Bit32s* output );
//Generate blocks of data in specific modes
template<SynthMode mode>
Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output );
Channel();
};
struct Chip {
//This is used as the base counter for vibrato and tremolo
Bit32u lfoCounter;
Bit32u lfoAdd;
Bit32u noiseCounter;
Bit32u noiseAdd;
Bit32u noiseValue;
//Frequency scales for the different multiplications
const Bit32u *freqMul/*[16]*/;
//Rates for decay and release for rate of this chip
const Bit32u *linearRates/*[76]*/;
//Best match attack rates for the rate of this chip
const Bit32u *attackRates/*[76]*/;
//18 channels with 2 operators each
Channel chan[18];
Bit8u reg104;
Bit8u reg08;
Bit8u reg04;
Bit8u regBD;
Bit8u vibratoIndex;
Bit8u tremoloIndex;
Bit8s vibratoSign;
Bit8u vibratoShift;
Bit8u tremoloValue;
Bit8u vibratoStrength;
Bit8u tremoloStrength;
//Mask for allowed wave forms
Bit8u waveFormMask;
//0 or -1 when enabled
Bit8s opl3Active;
//Return the maximum amount of samples before and LFO change
Bit32u ForwardLFO( Bit32u samples );
Bit32u ForwardNoise();
void WriteBD( Bit8u val );
void WriteReg(Bit32u reg, Bit8u val );
Bit32u WriteAddr( Bit32u port, Bit8u val );
void GenerateBlock2( Bitu samples, Bit32s* output );
void GenerateBlock2_Mix( Bitu samples, Bit32s* output );
void GenerateBlock3( Bitu samples, Bit32s* output );
void GenerateBlock3_Mix( Bitu samples, Bit32s* output );
//Update the synth handlers in all channels
void UpdateSynths();
void Generate( Bit32u samples );
void Setup( Bit32u r );
Chip();
};
struct Handler {
DBOPL::Chip chip;
void WritePan( Bit32u port, Bit8u val );
Bit32u WriteAddr( Bit32u port, Bit8u val );
void WriteReg( Bit32u addr, Bit8u val );
void GenerateArr(Bit32s *out, Bitu *samples);
void GenerateArr(Bit16s *out, Bitu *samples);
void GenerateArrMix(Bit32s *out, Bitu *samples);
void GenerateArrMix(Bit16s *out, Bitu *samples);
void Init( Bitu rate );
};
} //Namespace

View File

@ -1,80 +0,0 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "dosbox_opl3.h"
#include "dosbox/dbopl.h"
#include <new>
#include <cstdlib>
#include <assert.h>
DosBoxOPL3::DosBoxOPL3() :
OPLChipBaseBufferedT(),
m_chip(new DBOPL::Handler)
{
reset();
}
DosBoxOPL3::~DosBoxOPL3()
{
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
delete chip_r;
}
void DosBoxOPL3::setRate(uint32_t rate)
{
OPLChipBaseBufferedT::setRate(rate);
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
chip_r->~Handler();
new(chip_r) DBOPL::Handler;
chip_r->Init(effectiveRate());
}
void DosBoxOPL3::reset()
{
OPLChipBaseBufferedT::reset();
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
chip_r->~Handler();
new(chip_r) DBOPL::Handler;
chip_r->Init(effectiveRate());
}
void DosBoxOPL3::writeReg(uint16_t addr, uint8_t data)
{
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
chip_r->WriteReg(static_cast<Bit32u>(addr), data);
}
void DosBoxOPL3::writePan(uint16_t addr, uint8_t data)
{
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
chip_r->WritePan(static_cast<Bit32u>(addr), data);
}
void DosBoxOPL3::nativeGenerateN(int16_t *output, size_t frames)
{
DBOPL::Handler *chip_r = reinterpret_cast<DBOPL::Handler*>(m_chip);
Bitu frames_i = frames;
chip_r->GenerateArr(output, &frames_i);
}
const char *DosBoxOPL3::emulatorName()
{
return "DOSBox 0.74-r4111 OPL3";
}

View File

@ -1,44 +0,0 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef DOSBOX_OPL3_H
#define DOSBOX_OPL3_H
#include "opl_chip_base.h"
class DosBoxOPL3 final : public OPLChipBaseBufferedT<DosBoxOPL3>
{
void *m_chip;
public:
DosBoxOPL3();
~DosBoxOPL3() override;
bool canRunAtPcmRate() const override { return true; }
void setRate(uint32_t rate) override;
void reset() override;
void writeReg(uint16_t addr, uint8_t data) override;
void writePan(uint16_t addr, uint8_t data) override;
void nativePreGenerate() override {}
void nativePostGenerate() override {}
void nativeGenerateN(int16_t *output, size_t frames) override;
const char *emulatorName() override;
};
#endif // DOSBOX_OPL3_H

View File

@ -1,165 +0,0 @@
/*
* Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* Nuked OPL3 emulator.
* Thanks:
* MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh):
* Feedback and Rhythm part calculation information.
* forums.submarine.org.uk(carbon14, opl3):
* Tremolo and phase generator calculation information.
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
* OPL2 ROMs.
* siliconpr0n.org(John McMaster, digshadow):
* YMF262 and VRC VII decaps and die shots.
*
* version: 1.8
*/
#ifndef OPL_OPL3_H
#define OPL_OPL3_H
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
#endif
#define OPL_WRITEBUF_SIZE 1024
#define OPL_WRITEBUF_DELAY 2
typedef uintptr_t Bitu;
typedef intptr_t Bits;
typedef uint64_t Bit64u;
typedef int64_t Bit64s;
typedef uint32_t Bit32u;
typedef int32_t Bit32s;
typedef uint16_t Bit16u;
typedef int16_t Bit16s;
typedef uint8_t Bit8u;
typedef int8_t Bit8s;
typedef struct _opl3_slot opl3_slot;
typedef struct _opl3_channel opl3_channel;
typedef struct _opl3_chip opl3_chip;
struct _opl3_slot {
opl3_channel *channel;
opl3_chip *chip;
Bit16s out;
Bit16s fbmod;
Bit16s *mod;
Bit16s prout;
Bit16s eg_rout;
Bit16s eg_out;
Bit8u eg_inc;
Bit8u eg_gen;
Bit8u eg_rate;
Bit8u eg_ksl;
Bit8u *trem;
Bit8u reg_vib;
Bit8u reg_type;
Bit8u reg_ksr;
Bit8u reg_mult;
Bit8u reg_ksl;
Bit8u reg_tl;
Bit8u reg_ar;
Bit8u reg_dr;
Bit8u reg_sl;
Bit8u reg_rr;
Bit8u reg_wf;
Bit8u key;
Bit32u pg_reset;
Bit32u pg_phase;
Bit16u pg_phase_out;
Bit8u slot_num;
};
struct _opl3_channel {
opl3_slot *slotz[2];/*Don't use "slots" keyword to avoid conflict with Qt applications*/
opl3_channel *pair;
opl3_chip *chip;
Bit16s *out[4];
Bit8u chtype;
Bit16u f_num;
Bit8u block;
Bit8u fb;
Bit8u con;
Bit8u alg;
Bit8u ksv;
Bit16u cha, chb;
Bit16u chl, chr;
Bit8u ch_num;
};
typedef struct _opl3_writebuf {
Bit64u time;
Bit16u reg;
Bit8u data;
} opl3_writebuf;
struct _opl3_chip {
opl3_channel channel[18];
opl3_slot slot[36];
Bit16u timer;
Bit64u eg_timer;
Bit8u eg_timerrem;
Bit8u eg_state;
Bit8u eg_add;
Bit8u newm;
Bit8u nts;
Bit8u rhy;
Bit8u vibpos;
Bit8u vibshift;
Bit8u tremolo;
Bit8u tremolopos;
Bit8u tremoloshift;
Bit32u noise;
Bit16s zeromod;
Bit32s mixbuff[2];
Bit8u rm_hh_bit2;
Bit8u rm_hh_bit3;
Bit8u rm_hh_bit7;
Bit8u rm_hh_bit8;
Bit8u rm_tc_bit3;
Bit8u rm_tc_bit5;
/* OPL3L */
Bit32s rateratio;
Bit32s samplecnt;
Bit16s oldsamples[2];
Bit16s samples[2];
Bit64u writebuf_samplecnt;
Bit32u writebuf_cur;
Bit32u writebuf_last;
Bit64u writebuf_lasttime;
opl3_writebuf writebuf[OPL_WRITEBUF_SIZE];
};
void OPL3_Generate(opl3_chip *chip, Bit16s *buf);
void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf);
void OPL3_Reset(opl3_chip *chip, Bit32u samplerate);
void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v);
void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v);
void OPL3_WritePan(opl3_chip *chip, Bit16u reg, Bit8u v);
void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples);
void OPL3_GenerateStreamMix(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,156 +0,0 @@
/*
* Copyright (C) 2013-2016 Alexey Khokholov (Nuke.YKT)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Nuked OPL3 emulator.
* Thanks:
* MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh):
* Feedback and Rhythm part calculation information.
* forums.submarine.org.uk(carbon14, opl3):
* Tremolo and phase generator calculation information.
* OPLx decapsulated(Matthew Gambrell, Olli Niemitalo):
* OPL2 ROMs.
*
* version: 1.7.4
*/
#ifndef OPL_OPL3_H
#define OPL_OPL3_H
#include <inttypes.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define OPL_WRITEBUF_SIZE 1024
#define OPL_WRITEBUF_DELAY 2
typedef uintptr_t Bitu;
typedef intptr_t Bits;
typedef uint64_t Bit64u;
typedef int64_t Bit64s;
typedef uint32_t Bit32u;
typedef int32_t Bit32s;
typedef uint16_t Bit16u;
typedef int16_t Bit16s;
typedef uint8_t Bit8u;
typedef int8_t Bit8s;
typedef struct _opl3_slot opl3_slot;
typedef struct _opl3_channel opl3_channel;
typedef struct _opl3_chip opl3_chip;
struct _opl3_slot {
opl3_channel *channel;
opl3_chip *chip;
Bit16s out;
Bit16s fbmod;
Bit16s *mod;
Bit16s prout;
Bit16s eg_rout;
Bit16s eg_out;
Bit8u eg_inc;
Bit8u eg_gen;
Bit8u eg_rate;
Bit8u eg_ksl;
Bit8u *trem;
Bit8u reg_vib;
Bit8u reg_type;
Bit8u reg_ksr;
Bit8u reg_mult;
Bit8u reg_ksl;
Bit8u reg_tl;
Bit8u reg_ar;
Bit8u reg_dr;
Bit8u reg_sl;
Bit8u reg_rr;
Bit8u reg_wf;
Bit8u key;
Bit32u pg_phase;
Bit32u timer;
Bit16u maskzero;
Bit8u signpos;
Bit8u phaseshift;
};
struct _opl3_channel {
opl3_slot *slotz[2];/*Don't use "slots" keyword to avoid conflict with Qt applications*/
opl3_channel *pair;
opl3_chip *chip;
Bit16s *out[4];
Bit8u chtype;
Bit16u f_num;
Bit8u block;
Bit8u fb;
Bit8u con;
Bit8u alg;
Bit8u ksv;
Bit16u cha, chb;
Bit16u chl, chr;
};
typedef struct _opl3_writebuf {
Bit64u time;
Bit16u reg;
Bit8u data;
} opl3_writebuf;
struct _opl3_chip {
opl3_channel channel[18];
opl3_slot chipslot[36];
Bit16u timer;
Bit8u newm;
Bit8u nts;
Bit8u rhy;
Bit8u vibpos;
Bit8u vibshift;
Bit8u tremolo;
Bit8u tremolopos;
Bit8u tremoloshift;
Bit32u noise;
Bit16s zeromod;
Bit32s mixbuff[2];
/* OPL3L */
Bit32s rateratio;
Bit32s samplecnt;
Bit16s oldsamples[2];
Bit16s samples[2];
Bit64u writebuf_samplecnt;
Bit32u writebuf_cur;
Bit32u writebuf_last;
Bit64u writebuf_lasttime;
opl3_writebuf writebuf[OPL_WRITEBUF_SIZE];
};
void OPL3v17_Generate(opl3_chip *chip, Bit16s *buf);
void OPL3v17_GenerateResampled(opl3_chip *chip, Bit16s *buf);
void OPL3v17_Reset(opl3_chip *chip, Bit32u samplerate);
void OPL3v17_WritePan(opl3_chip *chip, Bit16u reg, Bit8u v);
void OPL3v17_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v);
void OPL3v17_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v);
void OPL3v17_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples);
void OPL3v17_GenerateStreamMix(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,75 +0,0 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "nuked_opl3.h"
#include "nuked/nukedopl3.h"
#include <cstring>
NukedOPL3::NukedOPL3() :
OPLChipBaseT()
{
m_chip = new opl3_chip;
setRate(m_rate);
}
NukedOPL3::~NukedOPL3()
{
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
delete chip_r;
}
void NukedOPL3::setRate(uint32_t rate)
{
OPLChipBaseT::setRate(rate);
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
std::memset(chip_r, 0, sizeof(opl3_chip));
OPL3_Reset(chip_r, rate);
}
void NukedOPL3::reset()
{
OPLChipBaseT::reset();
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
std::memset(chip_r, 0, sizeof(opl3_chip));
OPL3_Reset(chip_r, m_rate);
}
void NukedOPL3::writeReg(uint16_t addr, uint8_t data)
{
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
OPL3_WriteRegBuffered(chip_r, addr, data);
}
void NukedOPL3::writePan(uint16_t addr, uint8_t data)
{
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
OPL3_WritePan(chip_r, addr, data);
}
void NukedOPL3::nativeGenerate(int16_t *frame)
{
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
OPL3_Generate(chip_r, frame);
}
const char *NukedOPL3::emulatorName()
{
return "Nuked OPL3 (v 1.8)";
}

View File

@ -1,44 +0,0 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef NUKED_OPL3_H
#define NUKED_OPL3_H
#include "opl_chip_base.h"
class NukedOPL3 final : public OPLChipBaseT<NukedOPL3>
{
void *m_chip;
public:
NukedOPL3();
~NukedOPL3() override;
bool canRunAtPcmRate() const override { return false; }
void setRate(uint32_t rate) override;
void reset() override;
void writeReg(uint16_t addr, uint8_t data) override;
void writePan(uint16_t addr, uint8_t data) override;
void nativePreGenerate() override {}
void nativePostGenerate() override {}
void nativeGenerate(int16_t *frame) override;
const char *emulatorName() override;
};
#endif // NUKED_OPL3_H

View File

@ -1,75 +0,0 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "nuked_opl3_v174.h"
#include "nuked/nukedopl3_174.h"
#include <cstring>
NukedOPL3v174::NukedOPL3v174() :
OPLChipBaseT()
{
m_chip = new opl3_chip;
setRate(m_rate);
}
NukedOPL3v174::~NukedOPL3v174()
{
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
delete chip_r;
}
void NukedOPL3v174::setRate(uint32_t rate)
{
OPLChipBaseT::setRate(rate);
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
std::memset(chip_r, 0, sizeof(opl3_chip));
OPL3v17_Reset(chip_r, rate);
}
void NukedOPL3v174::reset()
{
OPLChipBaseT::reset();
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
std::memset(chip_r, 0, sizeof(opl3_chip));
OPL3v17_Reset(chip_r, m_rate);
}
void NukedOPL3v174::writeReg(uint16_t addr, uint8_t data)
{
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
OPL3v17_WriteReg(chip_r, addr, data);
}
void NukedOPL3v174::writePan(uint16_t addr, uint8_t data)
{
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
OPL3v17_WritePan(chip_r, addr, data);
}
void NukedOPL3v174::nativeGenerate(int16_t *frame)
{
opl3_chip *chip_r = reinterpret_cast<opl3_chip*>(m_chip);
OPL3v17_Generate(chip_r, frame);
}
const char *NukedOPL3v174::emulatorName()
{
return "Nuked OPL3 (v 1.7.4)";
}

View File

@ -1,44 +0,0 @@
/*
* Interfaces over Yamaha OPL3 (YMF262) chip emulators
*
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef NUKED_OPL3174_H
#define NUKED_OPL3174_H
#include "opl_chip_base.h"
class NukedOPL3v174 final : public OPLChipBaseT<NukedOPL3v174>
{
void *m_chip;
public:
NukedOPL3v174();
~NukedOPL3v174() override;
bool canRunAtPcmRate() const override { return false; }
void setRate(uint32_t rate) override;
void reset() override;
void writeReg(uint16_t addr, uint8_t data) override;
void writePan(uint16_t addr, uint8_t data) override;
void nativePreGenerate() override {}
void nativePostGenerate() override {}
void nativeGenerate(int16_t *frame) override;
const char *emulatorName() override;
};
#endif // NUKED_OPL3174_H

View File

@ -1,150 +0,0 @@
/*
* Copyright (C) 2017-2018 Vitaly Novichkov (Wohlstand)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef ONP_CHIP_BASE_H
#define ONP_CHIP_BASE_H
#include <stdint.h>
#include <stddef.h>
#if !defined(_MSC_VER) && (__cplusplus <= 199711L)
#define final
#define override
#endif
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
class VResampler;
#endif
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
extern void adl_audioTickHandler(void *instance, uint32_t chipId, uint32_t rate);
#endif
class OPLChipBase
{
public:
enum { nativeRate = 49716 };
protected:
uint32_t m_id;
uint32_t m_rate;
public:
OPLChipBase();
virtual ~OPLChipBase();
uint32_t chipId() const { return m_id; }
void setChipId(uint32_t id) { m_id = id; }
virtual bool canRunAtPcmRate() const = 0;
virtual bool isRunningAtPcmRate() const = 0;
virtual bool setRunningAtPcmRate(bool r) = 0;
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
virtual void setAudioTickHandlerInstance(void *instance) = 0;
#endif
virtual void setRate(uint32_t rate) = 0;
virtual uint32_t effectiveRate() const = 0;
virtual void reset() = 0;
virtual void writeReg(uint16_t addr, uint8_t data) = 0;
// extended
virtual void writePan(uint16_t addr, uint8_t data) { (void)addr; (void)data; }
virtual void nativePreGenerate() = 0;
virtual void nativePostGenerate() = 0;
virtual void nativeGenerate(int16_t *frame) = 0;
virtual void generate(int16_t *output, size_t frames) = 0;
virtual void generateAndMix(int16_t *output, size_t frames) = 0;
virtual void generate32(int32_t *output, size_t frames) = 0;
virtual void generateAndMix32(int32_t *output, size_t frames) = 0;
virtual const char* emulatorName() = 0;
private:
OPLChipBase(const OPLChipBase &c);
OPLChipBase &operator=(const OPLChipBase &c);
};
// A base class providing F-bounded generic and efficient implementations,
// supporting resampling of chip outputs
template <class T>
class OPLChipBaseT : public OPLChipBase
{
public:
OPLChipBaseT();
virtual ~OPLChipBaseT();
bool isRunningAtPcmRate() const override;
bool setRunningAtPcmRate(bool r) override;
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
void setAudioTickHandlerInstance(void *instance);
#endif
virtual void setRate(uint32_t rate) override;
uint32_t effectiveRate() const override;
virtual void reset() override;
void generate(int16_t *output, size_t frames) override;
void generateAndMix(int16_t *output, size_t frames) override;
void generate32(int32_t *output, size_t frames) override;
void generateAndMix32(int32_t *output, size_t frames) override;
private:
bool m_runningAtPcmRate;
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
void *m_audioTickHandlerInstance;
#endif
void nativeTick(int16_t *frame);
void setupResampler(uint32_t rate);
void resetResampler();
void resampledGenerate(int32_t *output);
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
VResampler *m_resampler;
#else
int32_t m_oldsamples[2];
int32_t m_samples[2];
int32_t m_samplecnt;
int32_t m_rateratio;
enum { rsm_frac = 10 };
#endif
// amplitude scale factors in and out of resampler, varying for chips;
// values are OK to "redefine", the static polymorphism will accept it.
enum { resamplerPreAmplify = 1, resamplerPostAttenuate = 1 };
};
// A base class which provides frame-by-frame interfaces on emulations which
// don't have a routine for it. It produces outputs in fixed size buffers.
// Fast register updates will suffer some latency because of buffering.
template <class T, unsigned Buffer = 256>
class OPLChipBaseBufferedT : public OPLChipBaseT<T>
{
public:
OPLChipBaseBufferedT()
: OPLChipBaseT<T>(), m_bufferIndex(0) {}
virtual ~OPLChipBaseBufferedT()
{}
public:
void reset() override;
void nativeGenerate(int16_t *frame) override;
protected:
virtual void nativeGenerateN(int16_t *output, size_t frames) = 0;
private:
unsigned m_bufferIndex;
int16_t m_buffer[2 * Buffer];
};
#include "opl_chip_base.tcc"
#endif // ONP_CHIP_BASE_H

View File

@ -1,294 +0,0 @@
#include "opl_chip_base.h"
#include <cmath>
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
#include <zita-resampler/vresampler.h>
#endif
#if !defined(LIKELY) && defined(__GNUC__)
#define LIKELY(x) __builtin_expect((x), 1)
#elif !defined(LIKELY)
#define LIKELY(x) (x)
#endif
#if !defined(UNLIKELY) && defined(__GNUC__)
#define UNLIKELY(x) __builtin_expect((x), 0)
#elif !defined(UNLIKELY)
#define UNLIKELY(x) (x)
#endif
/* OPLChipBase */
inline OPLChipBase::OPLChipBase() :
m_id(0),
m_rate(44100)
{
}
inline OPLChipBase::~OPLChipBase()
{
}
/* OPLChipBaseT */
template <class T>
OPLChipBaseT<T>::OPLChipBaseT()
: OPLChipBase(),
m_runningAtPcmRate(false)
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
,
m_audioTickHandlerInstance(NULL)
#endif
{
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
m_resampler = new VResampler;
#endif
setupResampler(m_rate);
}
template <class T>
OPLChipBaseT<T>::~OPLChipBaseT()
{
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
delete m_resampler;
#endif
}
template <class T>
bool OPLChipBaseT<T>::isRunningAtPcmRate() const
{
return m_runningAtPcmRate;
}
template <class T>
bool OPLChipBaseT<T>::setRunningAtPcmRate(bool r)
{
if(r != m_runningAtPcmRate)
{
if(r && !static_cast<T *>(this)->canRunAtPcmRate())
return false;
m_runningAtPcmRate = r;
static_cast<T *>(this)->setRate(m_rate);
}
return true;
}
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
template <class T>
void OPLChipBaseT<T>::setAudioTickHandlerInstance(void *instance)
{
m_audioTickHandlerInstance = instance;
}
#endif
template <class T>
void OPLChipBaseT<T>::setRate(uint32_t rate)
{
uint32_t oldRate = m_rate;
m_rate = rate;
if(rate != oldRate)
setupResampler(rate);
else
resetResampler();
}
template <class T>
uint32_t OPLChipBaseT<T>::effectiveRate() const
{
return m_runningAtPcmRate ? m_rate : (uint32_t)nativeRate;
}
template <class T>
void OPLChipBaseT<T>::reset()
{
resetResampler();
}
template <class T>
void OPLChipBaseT<T>::generate(int16_t *output, size_t frames)
{
static_cast<T *>(this)->nativePreGenerate();
for(size_t i = 0; i < frames; ++i)
{
int32_t frame[2];
static_cast<T *>(this)->resampledGenerate(frame);
for (unsigned c = 0; c < 2; ++c) {
int32_t temp = frame[c];
temp = (temp > -32768) ? temp : -32768;
temp = (temp < 32767) ? temp : 32767;
output[c] = (int16_t)temp;
}
output += 2;
}
static_cast<T *>(this)->nativePostGenerate();
}
template <class T>
void OPLChipBaseT<T>::generateAndMix(int16_t *output, size_t frames)
{
static_cast<T *>(this)->nativePreGenerate();
for(size_t i = 0; i < frames; ++i)
{
int32_t frame[2];
static_cast<T *>(this)->resampledGenerate(frame);
for (unsigned c = 0; c < 2; ++c) {
int32_t temp = (int32_t)output[c] + frame[c];
temp = (temp > -32768) ? temp : -32768;
temp = (temp < 32767) ? temp : 32767;
output[c] = (int16_t)temp;
}
output += 2;
}
static_cast<T *>(this)->nativePostGenerate();
}
template <class T>
void OPLChipBaseT<T>::generate32(int32_t *output, size_t frames)
{
static_cast<T *>(this)->nativePreGenerate();
for(size_t i = 0; i < frames; ++i)
{
static_cast<T *>(this)->resampledGenerate(output);
output += 2;
}
static_cast<T *>(this)->nativePostGenerate();
}
template <class T>
void OPLChipBaseT<T>::generateAndMix32(int32_t *output, size_t frames)
{
static_cast<T *>(this)->nativePreGenerate();
for(size_t i = 0; i < frames; ++i)
{
int32_t frame[2];
static_cast<T *>(this)->resampledGenerate(frame);
output[0] += frame[0];
output[1] += frame[1];
output += 2;
}
static_cast<T *>(this)->nativePostGenerate();
}
template <class T>
void OPLChipBaseT<T>::nativeTick(int16_t *frame)
{
#if defined(ADLMIDI_AUDIO_TICK_HANDLER)
adl_audioTickHandler(m_audioTickHandlerInstance, m_id, effectiveRate());
#endif
static_cast<T *>(this)->nativeGenerate(frame);
}
template <class T>
void OPLChipBaseT<T>::setupResampler(uint32_t rate)
{
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
m_resampler->setup(rate * (1.0 / 49716), 2, 48);
#else
m_oldsamples[0] = m_oldsamples[1] = 0;
m_samples[0] = m_samples[1] = 0;
m_samplecnt = 0;
m_rateratio = (int32_t)((rate << rsm_frac) / 49716);
#endif
}
template <class T>
void OPLChipBaseT<T>::resetResampler()
{
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
m_resampler->reset();
#else
m_oldsamples[0] = m_oldsamples[1] = 0;
m_samples[0] = m_samples[1] = 0;
m_samplecnt = 0;
#endif
}
#if defined(ADLMIDI_ENABLE_HQ_RESAMPLER)
template <class T>
void OPLChipBaseT<T>::resampledGenerate(int32_t *output)
{
if(UNLIKELY(m_runningAtPcmRate))
{
int16_t in[2];
static_cast<T *>(this)->nativeTick(in);
output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
return;
}
VResampler *rsm = m_resampler;
float scale = (float)T::resamplerPreAmplify /
(float)T::resamplerPostAttenuate;
float f_in[2];
float f_out[2];
rsm->inp_count = 0;
rsm->inp_data = f_in;
rsm->out_count = 1;
rsm->out_data = f_out;
while(rsm->process(), rsm->out_count != 0)
{
int16_t in[2];
static_cast<T *>(this)->nativeTick(in);
f_in[0] = scale * (float)in[0];
f_in[1] = scale * (float)in[1];
rsm->inp_count = 1;
rsm->inp_data = f_in;
rsm->out_count = 1;
rsm->out_data = f_out;
}
output[0] = static_cast<int32_t>(std::lround(f_out[0]));
output[1] = static_cast<int32_t>(std::lround(f_out[1]));
}
#else
template <class T>
void OPLChipBaseT<T>::resampledGenerate(int32_t *output)
{
if(UNLIKELY(m_runningAtPcmRate))
{
int16_t in[2];
static_cast<T *>(this)->nativeTick(in);
output[0] = (int32_t)in[0] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
output[1] = (int32_t)in[1] * T::resamplerPreAmplify / T::resamplerPostAttenuate;
return;
}
int32_t samplecnt = m_samplecnt;
const int32_t rateratio = m_rateratio;
while(samplecnt >= rateratio)
{
m_oldsamples[0] = m_samples[0];
m_oldsamples[1] = m_samples[1];
int16_t buffer[2];
static_cast<T *>(this)->nativeTick(buffer);
m_samples[0] = buffer[0] * T::resamplerPreAmplify;
m_samples[1] = buffer[1] * T::resamplerPreAmplify;
samplecnt -= rateratio;
}
output[0] = (int32_t)(((m_oldsamples[0] * (rateratio - samplecnt)
+ m_samples[0] * samplecnt) / rateratio)/T::resamplerPostAttenuate);
output[1] = (int32_t)(((m_oldsamples[1] * (rateratio - samplecnt)
+ m_samples[1] * samplecnt) / rateratio)/T::resamplerPostAttenuate);
m_samplecnt = samplecnt + (1 << rsm_frac);
}
#endif
/* OPLChipBaseBufferedT */
template <class T, unsigned Buffer>
void OPLChipBaseBufferedT<T, Buffer>::reset()
{
OPLChipBaseT<T>::reset();
m_bufferIndex = 0;
}
template <class T, unsigned Buffer>
void OPLChipBaseBufferedT<T, Buffer>::nativeGenerate(int16_t *frame)
{
unsigned bufferIndex = m_bufferIndex;
if(bufferIndex == 0)
static_cast<T *>(this)->nativeGenerateN(m_buffer, Buffer);
frame[0] = m_buffer[2 * bufferIndex];
frame[1] = m_buffer[2 * bufferIndex + 1];
bufferIndex = (bufferIndex + 1 < Buffer) ? (bufferIndex + 1) : 0;
m_bufferIndex = bufferIndex;
}

View File

@ -1,300 +0,0 @@
/*
* FileAndMemoryReader - a tiny helper to utify file reading from a disk and memory block
*
* Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#pragma once
#ifndef FILE_AND_MEM_READER_HHHH
#define FILE_AND_MEM_READER_HHHH
#include <string> // std::string
#include <cstdio> // std::fopen, std::fread, std::fseek, std::ftell, std::fclose, std::feof
#include <stdint.h> // uint*_t
#include <stddef.h> // size_t and friends
#ifdef _WIN32
#define NOMINMAX 1
#include <cstring> // std::strlen
#include <windows.h> // MultiByteToWideChar
#endif
/**
* @brief A little class gives able to read filedata from disk and also from a memory segment
*/
class FileAndMemReader
{
//! Currently loaded filename (empty for a memory blocks)
std::string m_file_name;
//! File reader descriptor
std::FILE *m_fp;
//! Memory pointer descriptor
const void *m_mp;
//! Size of memory block
size_t m_mp_size;
//! Cursor position in the memory block
size_t m_mp_tell;
public:
/**
* @brief Relation direction
*/
enum relTo
{
//! At begin position
SET = SEEK_SET,
//! At current position
CUR = SEEK_CUR,
//! At end position
END = SEEK_END
};
/**
* @brief C.O.: It's a constructor!
*/
FileAndMemReader() :
m_fp(NULL),
m_mp(NULL),
m_mp_size(0),
m_mp_tell(0)
{}
/**
* @brief C.O.: It's a destructor!
*/
~FileAndMemReader()
{
close();
}
/**
* @brief Open file from a disk
* @param path Path to the file in UTF-8 (even on Windows!)
*/
void openFile(const char *path)
{
if(m_fp)
this->close();//Close previously opened file first!
#if !defined(_WIN32) || defined(__WATCOMC__)
m_fp = std::fopen(path, "rb");
#else
wchar_t widePath[MAX_PATH];
int size = MultiByteToWideChar(CP_UTF8, 0, path, static_cast<int>(std::strlen(path)), widePath, MAX_PATH);
widePath[size] = '\0';
m_fp = _wfopen(widePath, L"rb");
#endif
m_file_name = path;
m_mp = NULL;
m_mp_size = 0;
m_mp_tell = 0;
}
/**
* @brief Open file from memory block
* @param mem Pointer to the memory block
* @param lenght Size of given block
*/
void openData(const void *mem, size_t lenght)
{
if(m_fp)
this->close();//Close previously opened file first!
m_fp = NULL;
m_mp = mem;
m_mp_size = lenght;
m_mp_tell = 0;
}
/**
* @brief Seek to given position
* @param pos Offset or position
* @param rel_to Relation (at begin, at current, or at end)
*/
void seek(long pos, int rel_to)
{
if(!this->isValid())
return;
if(m_fp)//If a file
{
std::fseek(m_fp, pos, rel_to);
}
else//If a memory block
{
switch(rel_to)
{
case SET:
m_mp_tell = static_cast<size_t>(pos);
break;
case END:
m_mp_tell = m_mp_size - static_cast<size_t>(pos);
break;
case CUR:
m_mp_tell = m_mp_tell + static_cast<size_t>(pos);
break;
}
if(m_mp_tell > m_mp_size)
m_mp_tell = m_mp_size;
}
}
/**
* @brief Seek to given position (unsigned integer 64 as relation. Negative values not supported)
* @param pos Offset or position
* @param rel_to Relation (at begin, at current, or at end)
*/
inline void seeku(uint64_t pos, int rel_to)
{
this->seek(static_cast<long>(pos), rel_to);
}
/**
* @brief Read the buffer from a file
* @param buf Pointer to the destination memory block
* @param num Number of elements
* @param size Size of one element
* @return Size
*/
size_t read(void *buf, size_t num, size_t size)
{
if(!this->isValid())
return 0;
if(m_fp)
return std::fread(buf, num, size, m_fp);
else
{
size_t pos = 0;
size_t maxSize = static_cast<size_t>(size * num);
while((pos < maxSize) && (m_mp_tell < m_mp_size))
{
reinterpret_cast<uint8_t *>(buf)[pos] = reinterpret_cast<const uint8_t *>(m_mp)[m_mp_tell];
m_mp_tell++;
pos++;
}
return pos / num;
}
}
/**
* @brief Get one byte and seek forward
* @return Readed byte or EOF (a.k.a. -1)
*/
int getc()
{
if(!this->isValid())
return -1;
if(m_fp)//If a file
{
return std::getc(m_fp);
}
else //If a memory block
{
if(m_mp_tell >= m_mp_size)
return -1;
int x = reinterpret_cast<const uint8_t *>(m_mp)[m_mp_tell];
m_mp_tell++;
return x;
}
}
/**
* @brief Returns current offset of cursor in a file
* @return Offset position
*/
size_t tell()
{
if(!this->isValid())
return 0;
if(m_fp)//If a file
return static_cast<size_t>(std::ftell(m_fp));
else//If a memory block
return m_mp_tell;
}
/**
* @brief Close the file
*/
void close()
{
if(m_fp)
std::fclose(m_fp);
m_fp = NULL;
m_mp = NULL;
m_mp_size = 0;
m_mp_tell = 0;
}
/**
* @brief Is file instance valid
* @return true if vaild
*/
bool isValid()
{
return (m_fp) || (m_mp);
}
/**
* @brief Is End Of File?
* @return true if end of file was reached
*/
bool eof()
{
if(!this->isValid())
return true;
if(m_fp)
return (std::feof(m_fp) != 0);
else
return m_mp_tell >= m_mp_size;
}
/**
* @brief Get a current file name
* @return File name of currently loaded file
*/
const std::string &fileName()
{
return m_file_name;
}
/**
* @brief Retrieve file size
* @return Size of file in bytes
*/
size_t fileSize()
{
if(!this->isValid())
return 0;
if(!m_fp)
return m_mp_size; //Size of memory block is well known
size_t old_pos = this->tell();
seek(0l, FileAndMemReader::END);
size_t file_size = this->tell();
seek(static_cast<long>(old_pos), FileAndMemReader::SET);
return file_size;
}
};
#endif /* FILE_AND_MEM_READER_HHHH */

View File

@ -1,588 +0,0 @@
/*
* Wohlstand's OPL3 Bank File - a bank format to store OPL3 timbre data and setup
*
* Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "wopl_file.h"
#include <string.h>
#include <stdlib.h>
static const char *wopl3_magic = "WOPL3-BANK\0";
static const char *wopli_magic = "WOPL3-INST\0";
static const uint16_t wopl_latest_version = 3;
#define WOPL_INST_SIZE_V2 62
#define WOPL_INST_SIZE_V3 66
static uint16_t toUint16LE(const uint8_t *arr)
{
uint16_t num = arr[0];
num |= ((arr[1] << 8) & 0xFF00);
return num;
}
static uint16_t toUint16BE(const uint8_t *arr)
{
uint16_t num = arr[1];
num |= ((arr[0] << 8) & 0xFF00);
return num;
}
static int16_t toSint16BE(const uint8_t *arr)
{
int16_t num = *(const int8_t *)(&arr[0]);
num *= 1 << 8;
num |= arr[1];
return num;
}
static void fromUint16LE(uint16_t in, uint8_t *arr)
{
arr[0] = in & 0x00FF;
arr[1] = (in >> 8) & 0x00FF;
}
static void fromUint16BE(uint16_t in, uint8_t *arr)
{
arr[1] = in & 0x00FF;
arr[0] = (in >> 8) & 0x00FF;
}
static void fromSint16BE(int16_t in, uint8_t *arr)
{
arr[1] = in & 0x00FF;
arr[0] = ((uint16_t)in >> 8) & 0x00FF;
}
WOPLFile *WOPL_Init(uint16_t melodic_banks, uint16_t percussive_banks)
{
WOPLFile *file = NULL;
if(melodic_banks == 0)
return NULL;
if(percussive_banks == 0)
return NULL;
file = (WOPLFile*)calloc(1, sizeof(WOPLFile));
if(!file)
return NULL;
file->banks_count_melodic = melodic_banks;
file->banks_count_percussion = percussive_banks;
file->banks_melodic = (WOPLBank*)calloc(1, sizeof(WOPLBank) * melodic_banks );
file->banks_percussive = (WOPLBank*)calloc(1, sizeof(WOPLBank) * percussive_banks );
return file;
}
void WOPL_Free(WOPLFile *file)
{
if(file)
{
if(file->banks_melodic)
free(file->banks_melodic);
if(file->banks_percussive)
free(file->banks_percussive);
free(file);
}
}
int WOPL_BanksCmp(const WOPLFile *bank1, const WOPLFile *bank2)
{
int res = 1;
res &= (bank1->version == bank2->version);
res &= (bank1->opl_flags == bank2->opl_flags);
res &= (bank1->volume_model == bank2->volume_model);
res &= (bank1->banks_count_melodic == bank2->banks_count_melodic);
res &= (bank1->banks_count_percussion == bank2->banks_count_percussion);
if(res)
{
int i;
for(i = 0; i < bank1->banks_count_melodic; i++)
res &= (memcmp(&bank1->banks_melodic[i], &bank2->banks_melodic[i], sizeof(WOPLBank)) == 0);
if(res)
{
for(i = 0; i < bank1->banks_count_percussion; i++)
res &= (memcmp(&bank1->banks_percussive[i], &bank2->banks_percussive[i], sizeof(WOPLBank)) == 0);
}
}
return res;
}
static void WOPL_parseInstrument(WOPLInstrument *ins, uint8_t *cursor, uint16_t version, uint8_t has_sounding_delays)
{
int l;
strncpy(ins->inst_name, (const char*)cursor, 32);
ins->inst_name[32] = '\0';
ins->note_offset1 = toSint16BE(cursor + 32);
ins->note_offset2 = toSint16BE(cursor + 34);
ins->midi_velocity_offset = (int8_t)cursor[36];
ins->second_voice_detune = (int8_t)cursor[37];
ins->percussion_key_number = cursor[38];
ins->inst_flags = cursor[39];
ins->fb_conn1_C0 = cursor[40];
ins->fb_conn2_C0 = cursor[41];
for(l = 0; l < 4; l++)
{
size_t off = 42 + (size_t)(l) * 5;
ins->operators[l].avekf_20 = cursor[off + 0];
ins->operators[l].ksl_l_40 = cursor[off + 1];
ins->operators[l].atdec_60 = cursor[off + 2];
ins->operators[l].susrel_80 = cursor[off + 3];
ins->operators[l].waveform_E0 = cursor[off + 4];
}
if((version >= 3) && has_sounding_delays)
{
ins->delay_on_ms = toUint16BE(cursor + 62);
ins->delay_off_ms = toUint16BE(cursor + 64);
}
}
static void WOPL_writeInstrument(WOPLInstrument *ins, uint8_t *cursor, uint16_t version, uint8_t has_sounding_delays)
{
int l;
strncpy((char*)cursor, ins->inst_name, 32);
fromSint16BE(ins->note_offset1, cursor + 32);
fromSint16BE(ins->note_offset2, cursor + 34);
cursor[36] = (uint8_t)ins->midi_velocity_offset;
cursor[37] = (uint8_t)ins->second_voice_detune;
cursor[38] = ins->percussion_key_number;
cursor[39] = ins->inst_flags;
cursor[40] = ins->fb_conn1_C0;
cursor[41] = ins->fb_conn2_C0;
for(l = 0; l < 4; l++)
{
size_t off = 42 + (size_t)(l) * 5;
cursor[off + 0] = ins->operators[l].avekf_20;
cursor[off + 1] = ins->operators[l].ksl_l_40;
cursor[off + 2] = ins->operators[l].atdec_60;
cursor[off + 3] = ins->operators[l].susrel_80;
cursor[off + 4] = ins->operators[l].waveform_E0;
}
if((version >= 3) && has_sounding_delays)
{
fromUint16BE(ins->delay_on_ms, cursor + 62);
fromUint16BE(ins->delay_off_ms, cursor + 64);
}
}
WOPLFile *WOPL_LoadBankFromMem(void *mem, size_t length, int *error)
{
WOPLFile *outFile = NULL;
uint16_t i = 0, j = 0, k = 0;
uint16_t version = 0;
uint16_t count_melodic_banks = 1;
uint16_t count_percusive_banks = 1;
uint8_t *cursor = (uint8_t *)mem;
WOPLBank *bankslots[2];
uint16_t bankslots_sizes[2];
#define SET_ERROR(err) \
{\
WOPL_Free(outFile);\
if(error)\
{\
*error = err;\
}\
}
#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; }
if(!cursor)
{
SET_ERROR(WOPL_ERR_NULL_POINTER);
return NULL;
}
{/* Magic number */
if(length < 11)
{
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
return NULL;
}
if(memcmp(cursor, wopl3_magic, 11) != 0)
{
SET_ERROR(WOPL_ERR_BAD_MAGIC);
return NULL;
}
GO_FORWARD(11);
}
{/* Version code */
if(length < 2)
{
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
return NULL;
}
version = toUint16LE(cursor);
if(version > wopl_latest_version)
{
SET_ERROR(WOPL_ERR_NEWER_VERSION);
return NULL;
}
GO_FORWARD(2);
}
{/* Header of WOPL */
uint8_t head[6];
if(length < 6)
{
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
return NULL;
}
memcpy(head, cursor, 6);
count_melodic_banks = toUint16BE(head);
count_percusive_banks = toUint16BE(head + 2);
GO_FORWARD(6);
outFile = WOPL_Init(count_melodic_banks, count_percusive_banks);
if(!outFile)
{
SET_ERROR(WOPL_ERR_OUT_OF_MEMORY);
return NULL;
}
outFile->version = version;
outFile->opl_flags = head[4];
outFile->volume_model = head[5];
}
bankslots_sizes[0] = count_melodic_banks;
bankslots[0] = outFile->banks_melodic;
bankslots_sizes[1] = count_percusive_banks;
bankslots[1] = outFile->banks_percussive;
if(version >= 2) /* Bank names and LSB/MSB titles */
{
for(i = 0; i < 2; i++)
{
for(j = 0; j < bankslots_sizes[i]; j++)
{
if(length < 34)
{
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
return NULL;
}
strncpy(bankslots[i][j].bank_name, (const char*)cursor, 32);
bankslots[i][j].bank_name[32] = '\0';
bankslots[i][j].bank_midi_lsb = cursor[32];
bankslots[i][j].bank_midi_msb = cursor[33];
GO_FORWARD(34);
}
}
}
{/* Read instruments data */
uint16_t insSize = 0;
if(version > 2)
insSize = WOPL_INST_SIZE_V3;
else
insSize = WOPL_INST_SIZE_V2;
for(i = 0; i < 2; i++)
{
if(length < (insSize * 128) * (size_t)bankslots_sizes[i])
{
SET_ERROR(WOPL_ERR_UNEXPECTED_ENDING);
return NULL;
}
for(j = 0; j < bankslots_sizes[i]; j++)
{
for(k = 0; k < 128; k++)
{
WOPLInstrument *ins = &bankslots[i][j].ins[k];
WOPL_parseInstrument(ins, cursor, version, 1);
GO_FORWARD(insSize);
}
}
}
}
#undef GO_FORWARD
#undef SET_ERROR
return outFile;
}
int WOPL_LoadInstFromMem(WOPIFile *file, void *mem, size_t length)
{
uint16_t version = 0;
uint8_t *cursor = (uint8_t *)mem;
uint16_t ins_size;
if(!cursor)
return WOPL_ERR_NULL_POINTER;
#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; }
{/* Magic number */
if(length < 11)
return WOPL_ERR_UNEXPECTED_ENDING;
if(memcmp(cursor, wopli_magic, 11) != 0)
return WOPL_ERR_BAD_MAGIC;
GO_FORWARD(11);
}
{/* Version code */
if(length < 2)
return WOPL_ERR_UNEXPECTED_ENDING;
version = toUint16LE(cursor);
if(version > wopl_latest_version)
return WOPL_ERR_NEWER_VERSION;
GO_FORWARD(2);
}
file->version = version;
{/* is drum flag */
if(length < 1)
return WOPL_ERR_UNEXPECTED_ENDING;
file->is_drum = *cursor;
GO_FORWARD(1);
}
if(version > 2)
/* Skip sounding delays are not part of single-instrument file
* two sizes of uint16_t will be subtracted */
ins_size = WOPL_INST_SIZE_V3 - (sizeof(uint16_t) * 2);
else
ins_size = WOPL_INST_SIZE_V2;
if(length < ins_size)
return WOPL_ERR_UNEXPECTED_ENDING;
WOPL_parseInstrument(&file->inst, cursor, version, 0);
GO_FORWARD(ins_size);
return WOPL_ERR_OK;
#undef GO_FORWARD
}
size_t WOPL_CalculateBankFileSize(WOPLFile *file, uint16_t version)
{
size_t final_size = 0;
size_t ins_size = 0;
if(version == 0)
version = wopl_latest_version;
if(!file)
return 0;
final_size += 11 + 2 + 2 + 2 + 1 + 1;
/*
* Magic number,
* Version,
* Count of melodic banks,
* Count of percussive banks,
* Chip specific flags
* Volume Model
*/
if(version >= 2)
{
/* Melodic banks meta-data */
final_size += (32 + 1 + 1) * file->banks_count_melodic;
/* Percussive banks meta-data */
final_size += (32 + 1 + 1) * file->banks_count_percussion;
}
if(version >= 3)
ins_size = WOPL_INST_SIZE_V3;
else
ins_size = WOPL_INST_SIZE_V2;
/* Melodic instruments */
final_size += (ins_size * 128) * file->banks_count_melodic;
/* Percusive instruments */
final_size += (ins_size * 128) * file->banks_count_percussion;
return final_size;
}
size_t WOPL_CalculateInstFileSize(WOPIFile *file, uint16_t version)
{
size_t final_size = 0;
size_t ins_size = 0;
if(version == 0)
version = wopl_latest_version;
if(!file)
return 0;
final_size += 11 + 2 + 1;
/*
* Magic number,
* version,
* is percussive instrument
*/
if(version > 2)
/* Skip sounding delays are not part of single-instrument file
* two sizes of uint16_t will be subtracted */
ins_size = WOPL_INST_SIZE_V3 - (sizeof(uint16_t) * 2);
else
ins_size = WOPL_INST_SIZE_V2;
final_size += ins_size;
return final_size;
}
int WOPL_SaveBankToMem(WOPLFile *file, void *dest_mem, size_t length, uint16_t version, uint16_t force_gm)
{
uint8_t *cursor = (uint8_t *)dest_mem;
uint16_t ins_size = 0;
uint16_t i, j, k;
uint16_t banks_melodic = force_gm ? 1 : file->banks_count_melodic;
uint16_t banks_percusive = force_gm ? 1 : file->banks_count_percussion;
WOPLBank *bankslots[2];
uint16_t bankslots_sizes[2];
if(version == 0)
version = wopl_latest_version;
#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; }
if(length < 11)
return WOPL_ERR_UNEXPECTED_ENDING;
memcpy(cursor, wopl3_magic, 11);
GO_FORWARD(11);
if(length < 2)
return WOPL_ERR_UNEXPECTED_ENDING;
fromUint16LE(version, cursor);
GO_FORWARD(2);
if(length < 2)
return WOPL_ERR_UNEXPECTED_ENDING;
fromUint16BE(banks_melodic, cursor);
GO_FORWARD(2);
if(length < 2)
return WOPL_ERR_UNEXPECTED_ENDING;
fromUint16BE(banks_percusive, cursor);
GO_FORWARD(2);
if(length < 2)
return WOPL_ERR_UNEXPECTED_ENDING;
cursor[0] = file->opl_flags;
cursor[1] = file->volume_model;
GO_FORWARD(2);
bankslots[0] = file->banks_melodic;
bankslots_sizes[0] = banks_melodic;
bankslots[1] = file->banks_percussive;
bankslots_sizes[1] = banks_percusive;
if(version >= 2)
{
for(i = 0; i < 2; i++)
{
for(j = 0; j < bankslots_sizes[i]; j++)
{
if(length < 34)
return WOPL_ERR_UNEXPECTED_ENDING;
strncpy((char*)cursor, bankslots[i][j].bank_name, 32);
cursor[32] = bankslots[i][j].bank_midi_lsb;
cursor[33] = bankslots[i][j].bank_midi_msb;
GO_FORWARD(34);
}
}
}
{/* Write instruments data */
if(version >= 3)
ins_size = WOPL_INST_SIZE_V3;
else
ins_size = WOPL_INST_SIZE_V2;
for(i = 0; i < 2; i++)
{
if(length < (ins_size * 128) * (size_t)bankslots_sizes[i])
return WOPL_ERR_UNEXPECTED_ENDING;
for(j = 0; j < bankslots_sizes[i]; j++)
{
for(k = 0; k < 128; k++)
{
WOPLInstrument *ins = &bankslots[i][j].ins[k];
WOPL_writeInstrument(ins, cursor, version, 1);
GO_FORWARD(ins_size);
}
}
}
}
return WOPL_ERR_OK;
#undef GO_FORWARD
}
int WOPL_SaveInstToMem(WOPIFile *file, void *dest_mem, size_t length, uint16_t version)
{
uint8_t *cursor = (uint8_t *)dest_mem;
uint16_t ins_size;
if(!cursor)
return WOPL_ERR_NULL_POINTER;
if(version == 0)
version = wopl_latest_version;
#define GO_FORWARD(bytes) { cursor += bytes; length -= bytes; }
{/* Magic number */
if(length < 11)
return WOPL_ERR_UNEXPECTED_ENDING;
memcpy(cursor, wopli_magic, 11);
GO_FORWARD(11);
}
{/* Version code */
if(length < 2)
return WOPL_ERR_UNEXPECTED_ENDING;
fromUint16LE(version, cursor);
GO_FORWARD(2);
}
{/* is drum flag */
if(length < 1)
return WOPL_ERR_UNEXPECTED_ENDING;
*cursor = file->is_drum;
GO_FORWARD(1);
}
if(version > 2)
/* Skip sounding delays are not part of single-instrument file
* two sizes of uint16_t will be subtracted */
ins_size = WOPL_INST_SIZE_V3 - (sizeof(uint16_t) * 2);
else
ins_size = WOPL_INST_SIZE_V2;
if(length < ins_size)
return WOPL_ERR_UNEXPECTED_ENDING;
WOPL_writeInstrument(&file->inst, cursor, version, 0);
GO_FORWARD(ins_size);
return WOPL_ERR_OK;
#undef GO_FORWARD
}

View File

@ -1,293 +0,0 @@
/*
* Wohlstand's OPL3 Bank File - a bank format to store OPL3 timbre data and setup
*
* Copyright (c) 2015-2018 Vitaly Novichkov <admin@wohlnet.ru>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef WOPL_FILE_H
#define WOPL_FILE_H
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(__STDC_VERSION__) || (defined(__STDC_VERSION__) && (__STDC_VERSION__ < 199901L)) \
|| defined(__STRICT_ANSI__) || !defined(__cplusplus)
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef signed short int int16_t;
typedef unsigned short int uint16_t;
#endif
/* Global OPL flags */
typedef enum WOPLFileFlags
{
/* Enable Deep-Tremolo flag */
WOPL_FLAG_DEEP_TREMOLO = 0x01,
/* Enable Deep-Vibrato flag */
WOPL_FLAG_DEEP_VIBRATO = 0x02
} WOPLFileFlags;
/* Volume scaling model implemented in the libADLMIDI */
typedef enum WOPL_VolumeModel
{
WOPL_VM_Generic = 0,
WOPL_VM_Native,
WOPL_VM_DMX,
WOPL_VM_Apogee,
WOPL_VM_Win9x
} WOPL_VolumeModel;
typedef enum WOPL_InstrumentFlags
{
/* Is two-operator single-voice instrument (no flags) */
WOPL_Ins_2op = 0x00,
/* Is true four-operator instrument */
WOPL_Ins_4op = 0x01,
/* Is pseudo four-operator (two 2-operator voices) instrument */
WOPL_Ins_Pseudo4op = 0x02,
/* Is a blank instrument entry */
WOPL_Ins_IsBlank = 0x04,
/* RythmMode flags mask */
WOPL_RhythmModeMask = 0x38,
/* Mask of the flags range */
WOPL_Ins_ALL_MASK = 0x07
} WOPL_InstrumentFlags;
typedef enum WOPL_RhythmMode
{
/* RythmMode: BassDrum */
WOPL_RM_BassDrum = 0x08,
/* RythmMode: Snare */
WOPL_RM_Snare = 0x10,
/* RythmMode: TomTom */
WOPL_RM_TomTom = 0x18,
/* RythmMode: Cymbell */
WOPL_RM_Cymbal = 0x20,
/* RythmMode: HiHat */
WOPL_RM_HiHat = 0x28
} WOPL_RhythmMode;
/* DEPRECATED: It has typo. Don't use it! */
typedef WOPL_RhythmMode WOPL_RythmMode;
/* Error codes */
typedef enum WOPL_ErrorCodes
{
WOPL_ERR_OK = 0,
/* Magic number is not maching */
WOPL_ERR_BAD_MAGIC,
/* Too short file */
WOPL_ERR_UNEXPECTED_ENDING,
/* Zero banks count */
WOPL_ERR_INVALID_BANKS_COUNT,
/* Version of file is newer than supported by current version of library */
WOPL_ERR_NEWER_VERSION,
/* Out of memory */
WOPL_ERR_OUT_OF_MEMORY,
/* Given null pointer memory data */
WOPL_ERR_NULL_POINTER
} WOPL_ErrorCodes;
/* Operator indeces inside of Instrument Entry */
#define WOPL_OP_CARRIER1 0
#define WOPL_OP_MODULATOR1 1
#define WOPL_OP_CARRIER2 2
#define WOPL_OP_MODULATOR2 3
/* OPL3 Oerators data */
typedef struct WOPLOperator
{
/* AM/Vib/Env/Ksr/FMult characteristics */
uint8_t avekf_20;
/* Key Scale Level / Total level register data */
uint8_t ksl_l_40;
/* Attack / Decay */
uint8_t atdec_60;
/* Systain and Release register data */
uint8_t susrel_80;
/* Wave form */
uint8_t waveform_E0;
} WOPLOperator;
/* Instrument entry */
typedef struct WOPLInstrument
{
/* Title of the instrument */
char inst_name[34];
/* MIDI note key (half-tone) offset for an instrument (or a first voice in pseudo-4-op mode) */
int16_t note_offset1;
/* MIDI note key (half-tone) offset for a second voice in pseudo-4-op mode */
int16_t note_offset2;
/* MIDI note velocity offset (taken from Apogee TMB format) */
int8_t midi_velocity_offset;
/* Second voice detune level (taken from DMX OP2) */
int8_t second_voice_detune;
/* Percussion MIDI base tone number at which this drum will be played */
uint8_t percussion_key_number;
/* Enum WOPL_InstrumentFlags */
uint8_t inst_flags;
/* Feedback&Connection register for first and second operators */
uint8_t fb_conn1_C0;
/* Feedback&Connection register for third and fourth operators */
uint8_t fb_conn2_C0;
/* Operators register data */
WOPLOperator operators[4];
/* Millisecond delay of sounding while key is on */
uint16_t delay_on_ms;
/* Millisecond delay of sounding after key off */
uint16_t delay_off_ms;
} WOPLInstrument;
/* Bank entry */
typedef struct WOPLBank
{
/* Name of bank */
char bank_name[33];
/* MIDI Bank LSB code */
uint8_t bank_midi_lsb;
/* MIDI Bank MSB code */
uint8_t bank_midi_msb;
/* Instruments data of this bank */
WOPLInstrument ins[128];
} WOPLBank;
/* Instrument data file */
typedef struct WOPIFile
{
/* Version of instrument file */
uint16_t version;
/* Is this a percussion instrument */
uint8_t is_drum;
/* Instrument data */
WOPLInstrument inst;
} WOPIFile;
/* Bank data file */
typedef struct WOPLFile
{
/* Version of bank file */
uint16_t version;
/* Count of melodic banks in this file */
uint16_t banks_count_melodic;
/* Count of percussion banks in this file */
uint16_t banks_count_percussion;
/* Enum WOPLFileFlags */
uint8_t opl_flags;
/* Enum WOPL_VolumeModel */
uint8_t volume_model;
/* dynamically allocated data Melodic banks array */
WOPLBank *banks_melodic;
/* dynamically allocated data Percussive banks array */
WOPLBank *banks_percussive;
} WOPLFile;
/**
* @brief Initialize blank WOPL data structure with allocated bank data
* @param melodic_banks Count of melodic banks
* @param percussive_banks Count of percussive banks
* @return pointer to heap-allocated WOPL data structure or NULL when out of memory or incorrectly given banks counts
*/
extern WOPLFile *WOPL_Init(uint16_t melodic_banks, uint16_t percussive_banks);
/**
* @brief Clean up WOPL data file (all allocated bank arrays will be fried too)
* @param file pointer to heap-allocated WOPL data structure
*/
extern void WOPL_Free(WOPLFile *file);
/**
* @brief Compare two bank entries
* @param bank1 First bank
* @param bank2 Second bank
* @return 1 if banks are equal or 0 if there are different
*/
extern int WOPL_BanksCmp(const WOPLFile *bank1, const WOPLFile *bank2);
/**
* @brief Load WOPL bank file from the memory.
* WOPL data structure will be allocated. (don't forget to clear it with WOPL_Free() after use!)
* @param mem Pointer to memory block contains raw WOPL bank file data
* @param length Length of given memory block
* @param error pointer to integer to return an error code. Pass NULL if you don't want to use error codes.
* @return Heap-allocated WOPL file data structure or NULL if any error has occouped
*/
extern WOPLFile *WOPL_LoadBankFromMem(void *mem, size_t length, int *error);
/**
* @brief Load WOPI instrument file from the memory.
* You must allocate WOPIFile structure by yourself and give the pointer to it.
* @param file Pointer to destinition WOPIFile structure to fill it with parsed data.
* @param mem Pointer to memory block contains raw WOPI instrument file data
* @param length Length of given memory block
* @return 0 if no errors occouped, or an error code of WOPL_ErrorCodes enumeration
*/
extern int WOPL_LoadInstFromMem(WOPIFile *file, void *mem, size_t length);
/**
* @brief Calculate the size of the output memory block
* @param file Heap-allocated WOPL file data structure
* @param version Destinition version of the file
* @return Size of the raw WOPL file data
*/
extern size_t WOPL_CalculateBankFileSize(WOPLFile *file, uint16_t version);
/**
* @brief Calculate the size of the output memory block
* @param file Pointer to WOPI file data structure
* @param version Destinition version of the file
* @return Size of the raw WOPI file data
*/
extern size_t WOPL_CalculateInstFileSize(WOPIFile *file, uint16_t version);
/**
* @brief Write raw WOPL into given memory block
* @param file Heap-allocated WOPL file data structure
* @param dest_mem Destinition memory block pointer
* @param length Length of destinition memory block
* @param version Wanted WOPL version
* @param force_gm Force GM set in saved bank file
* @return Error code or 0 on success
*/
extern int WOPL_SaveBankToMem(WOPLFile *file, void *dest_mem, size_t length, uint16_t version, uint16_t force_gm);
/**
* @brief Write raw WOPI into given memory block
* @param file Pointer to WOPI file data structure
* @param dest_mem Destinition memory block pointer
* @param length Length of destinition memory block
* @param version Wanted WOPI version
* @return Error code or 0 on success
*/
extern int WOPL_SaveInstToMem(WOPIFile *file, void *dest_mem, size_t length, uint16_t version);
#ifdef __cplusplus
}
#endif
#endif /* WOPL_FILE_H */

View File

@ -1,112 +0,0 @@
cmake_minimum_required(VERSION 2.8.7)
#make_release_only()
project(asmjit C)
set(ASMJITNAME asmjit)
add_definitions(-DASMJIT_BUILD_EMBED)
add_definitions(-DASMJIT_STATIC)
if(MSVC)
set(CMAKE_DEBUG_POSTFIX "d")
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
endif()
if(APPLE)
# Suppress stdlib.h:334:6: warning: pointer is missing a nullability type specifier (_Nonnull, _Nullable, or _Null_unspecified)
add_definitions(-Wno-nullability-completeness)
endif()
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
set(ASMJIT_PUBLIC_HDRS
asmjit/arm.h
asmjit/asmjit.h
asmjit/asmjit_apibegin.h
asmjit/asmjit_apiend.h
asmjit/asmjit_build.h
asmjit/base.h
asmjit/base/arch.h
asmjit/base/assembler.h
asmjit/base/codebuilder.h
asmjit/base/codecompiler.h
asmjit/base/codeemitter.h
asmjit/base/codeholder.h
asmjit/base/constpool.h
asmjit/base/cpuinfo.h
asmjit/base/func.h
asmjit/base/globals.h
asmjit/base/inst.h
asmjit/base/logging.h
asmjit/base/misc_p.h
asmjit/base/operand.h
asmjit/base/osutils.h
asmjit/base/regalloc_p.h
asmjit/base/runtime.h
asmjit/base/simdtypes.h
asmjit/base/string.h
asmjit/base/utils.h
asmjit/base/vmem.h
asmjit/base/zone.h
asmjit/x86.h
asmjit/x86/x86assembler.h
asmjit/x86/x86builder.h
asmjit/x86/x86compiler.h
asmjit/x86/x86emitter.h
asmjit/x86/x86globals.h
asmjit/x86/x86inst.h
asmjit/x86/x86instimpl_p.h
asmjit/x86/x86internal_p.h
asmjit/x86/x86logging_p.h
asmjit/x86/x86misc.h
asmjit/x86/x86operand.h
asmjit/x86/x86regalloc_p.h
)
set(ASMJIT_SRCS
asmjit/base/arch.cpp
asmjit/base/assembler.cpp
asmjit/base/codebuilder.cpp
asmjit/base/codecompiler.cpp
asmjit/base/codeemitter.cpp
asmjit/base/codeholder.cpp
asmjit/base/constpool.cpp
asmjit/base/cpuinfo.cpp
asmjit/base/func.cpp
asmjit/base/globals.cpp
asmjit/base/inst.cpp
asmjit/base/logging.cpp
asmjit/base/operand.cpp
asmjit/base/osutils.cpp
asmjit/base/regalloc.cpp
asmjit/base/runtime.cpp
asmjit/base/string.cpp
asmjit/base/utils.cpp
asmjit/base/vmem.cpp
asmjit/base/zone.cpp
asmjit/x86/x86assembler.cpp
asmjit/x86/x86builder.cpp
asmjit/x86/x86compiler.cpp
asmjit/x86/x86inst.cpp
asmjit/x86/x86instimpl.cpp
asmjit/x86/x86internal.cpp
asmjit/x86/x86logging.cpp
asmjit/x86/x86operand.cpp
asmjit/x86/x86operand_regs.cpp
asmjit/x86/x86regalloc.cpp
)
add_library(${ASMJITNAME} STATIC ${ASMJIT_SRCS} ${ASMJIT_PUBLIC_HDRS})
set_target_properties(${ASMJITNAME} PROPERTIES OUTPUT_NAME asmjit)
if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL )
install(TARGETS ${ASMJITNAME}
RUNTIME DESTINATION bin
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib )
endif()
if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL )
install(FILES ${ASMJIT_PUBLIC_HDRS} DESTINATION include)
endif()

View File

@ -1,21 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_ARM_H
#define _ASMJIT_ARM_H
// [Dependencies]
#include "./base.h"
#include "./arm/armassembler.h"
#include "./arm/armbuilder.h"
#include "./arm/armcompiler.h"
#include "./arm/arminst.h"
#include "./arm/armoperand.h"
// [Guard]
#endif // _ASMJIT_ARM_H

View File

@ -1,47 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_ASMJIT_H
#define _ASMJIT_ASMJIT_H
// ============================================================================
// [asmjit_mainpage]
// ============================================================================
//! \mainpage
//!
//! AsmJit - Complete x86/x64 JIT and Remote Assembler for C++.
//!
//! Introduction provided by the project page at https://github.com/asmjit/asmjit.
//! \defgroup asmjit_base AsmJit Base API (architecture independent)
//!
//! \brief Backend Neutral API.
//! \defgroup asmjit_x86 AsmJit X86/X64 API
//!
//! \brief X86/X64 Backend API.
//! \defgroup asmjit_arm AsmJit ARM32/ARM64 API
//!
//! \brief ARM32/ARM64 Backend API.
// [Dependencies]
#include "./base.h"
// [X86/X64]
#if defined(ASMJIT_BUILD_X86)
#include "./x86.h"
#endif // ASMJIT_BUILD_X86
// [ARM32/ARM64]
#if defined(ASMJIT_BUILD_ARM)
#include "./arm.h"
#endif // ASMJIT_BUILD_ARM
// [Guard]
#endif // _ASMJIT_ASMJIT_H

View File

@ -1,117 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Dependencies]
#if !defined(_ASMJIT_BUILD_H)
# include "./build.h"
#endif // !_ASMJIT_BUILD_H
// [Guard]
#if !defined(ASMJIT_API_SCOPE)
# define ASMJIT_API_SCOPE
#else
# error "[asmjit] api-scope is already active, previous scope not closed by asmjit_apiend.h?"
#endif // ASMJIT_API_SCOPE
// ============================================================================
// [C++ Support]
// ============================================================================
// [NoExcept]
#if !ASMJIT_CC_HAS_NOEXCEPT && !defined(noexcept)
# define noexcept ASMJIT_NOEXCEPT
# define ASMJIT_UNDEF_NOEXCEPT
#endif // !ASMJIT_CC_HAS_NOEXCEPT && !noexcept
// [NullPtr]
#if !ASMJIT_CC_HAS_NULLPTR && !defined(nullptr)
# define nullptr NULL
# define ASMJIT_UNDEF_NULLPTR
#endif // !ASMJIT_CC_HAS_NULLPTR && !nullptr
// [Override]
#if !ASMJIT_CC_HAS_OVERRIDE && !defined(override)
# define override
# define ASMJIT_UNDEF_OVERRIDE
#endif // !ASMJIT_CC_HAS_OVERRIDE && !override
// ============================================================================
// [Compiler Support]
// ============================================================================
// [Clang]
#if ASMJIT_CC_CLANG
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wc++11-extensions"
# pragma clang diagnostic ignored "-Wconstant-logical-operand"
# pragma clang diagnostic ignored "-Wunnamed-type-template-args"
#endif // ASMJIT_CC_CLANG
// [GCC]
#if ASMJIT_CC_GCC
# pragma GCC diagnostic push
#endif // ASMJIT_CC_GCC
// [MSC]
#if ASMJIT_CC_MSC
# pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4201) // nameless struct/union
# pragma warning(disable: 4244) // '+=' : conversion from 'int' to 'x', possible loss of data
# pragma warning(disable: 4251) // struct needs to have dll-interface to be used by clients of struct ...
# pragma warning(disable: 4275) // non dll-interface struct ... used as base for dll-interface struct
# pragma warning(disable: 4355) // this used in base member initializer list
# pragma warning(disable: 4480) // specifying underlying type for enum
# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false'
# if _MSC_VER < 1900
# if !defined(vsnprintf)
# define ASMJIT_UNDEF_VSNPRINTF
# define vsnprintf _vsnprintf
# endif // !vsnprintf
# if !defined(snprintf)
# define ASMJIT_UNDEF_SNPRINTF
# define snprintf _snprintf
# endif // !snprintf
# endif
#endif // ASMJIT_CC_MSC
// ============================================================================
// [Custom Macros]
// ============================================================================
// [ASMJIT_NON...]
#if ASMJIT_CC_HAS_DELETE_FUNCTION
#define ASMJIT_NONCONSTRUCTIBLE(...) \
private: \
__VA_ARGS__() = delete; \
__VA_ARGS__(const __VA_ARGS__& other) = delete; \
__VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; \
public:
#define ASMJIT_NONCOPYABLE(...) \
private: \
__VA_ARGS__(const __VA_ARGS__& other) = delete; \
__VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; \
public:
#else
#define ASMJIT_NONCONSTRUCTIBLE(...) \
private: \
inline __VA_ARGS__(); \
inline __VA_ARGS__(const __VA_ARGS__& other); \
inline __VA_ARGS__& operator=(const __VA_ARGS__& other); \
public:
#define ASMJIT_NONCOPYABLE(...) \
private: \
inline __VA_ARGS__(const __VA_ARGS__& other); \
inline __VA_ARGS__& operator=(const __VA_ARGS__& other); \
public:
#endif // ASMJIT_CC_HAS_DELETE_FUNCTION
// [ASMJIT_ENUM]
#if defined(_MSC_VER) && _MSC_VER >= 1400
# define ASMJIT_ENUM(NAME) enum NAME : uint32_t
#else
# define ASMJIT_ENUM(NAME) enum NAME
#endif

View File

@ -1,74 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#if defined(ASMJIT_API_SCOPE)
# undef ASMJIT_API_SCOPE
#else
# error "[asmjit] api-scope not active, forgot to include asmjit_apibegin.h?"
#endif // ASMJIT_API_SCOPE
// ============================================================================
// [C++ Support]
// ============================================================================
// [NoExcept]
#if defined(ASMJIT_UNDEF_NOEXCEPT)
# undef noexcept
# undef ASMJIT_UNDEF_NOEXCEPT
#endif // ASMJIT_UNDEF_NOEXCEPT
// [NullPtr]
#if defined(ASMJIT_UNDEF_NULLPTR)
# undef nullptr
# undef ASMJIT_UNDEF_NULLPTR
#endif // ASMJIT_UNDEF_NULLPTR
// [Override]
#if defined(ASMJIT_UNDEF_OVERRIDE)
# undef override
# undef ASMJIT_UNDEF_OVERRIDE
#endif // ASMJIT_UNDEF_OVERRIDE
// ============================================================================
// [Compiler Support]
// ============================================================================
// [Clang]
#if ASMJIT_CC_CLANG
# pragma clang diagnostic pop
#endif // ASMJIT_CC_CLANG
// [GCC]
#if ASMJIT_CC_GCC
# pragma GCC diagnostic pop
#endif // ASMJIT_CC_GCC
// [MSC]
#if ASMJIT_CC_MSC
# pragma warning(pop)
# if _MSC_VER < 1900
# if defined(ASMJIT_UNDEF_VSNPRINTF)
# undef vsnprintf
# undef ASMJIT_UNDEF_VSNPRINTF
# endif // ASMJIT_UNDEF_VSNPRINTF
# if defined(ASMJIT_UNDEF_SNPRINTF)
# undef snprintf
# undef ASMJIT_UNDEF_SNPRINTF
# endif // ASMJIT_UNDEF_SNPRINTF
# endif
#endif // ASMJIT_CC_MSC
// ============================================================================
// [Custom Macros]
// ============================================================================
// [ASMJIT_NON...]
#undef ASMJIT_NONCONSTRUCTIBLE
#undef ASMJIT_NONCOPYABLE
// [ASMJIT_ENUM]
#undef ASMJIT_ENUM

View File

@ -1,949 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BUILD_H
#define _ASMJIT_BUILD_H
// ============================================================================
// [asmjit::Build - Configuration]
// ============================================================================
// AsmJit is by default compiled only for a host processor for the purpose of
// JIT code generation. Both Assembler and CodeCompiler emitters are compiled
// by default. Preprocessor macros can be used to change the default behavior.
// External Config File
// --------------------
//
// Define in case your configuration is generated in an external file to be
// included.
#if defined(ASMJIT_CONFIG_FILE)
# include ASMJIT_CONFIG_FILE
#endif // ASMJIT_CONFIG_FILE
// AsmJit Static Builds and Embedding
// ----------------------------------
//
// These definitions can be used to enable static library build. Embed is used
// when AsmJit's source code is embedded directly in another project, implies
// static build as well.
//
// #define ASMJIT_EMBED // Asmjit is embedded (implies ASMJIT_STATIC).
// #define ASMJIT_STATIC // Define to enable static-library build.
// AsmJit Build Modes
// ------------------
//
// These definitions control the build mode and tracing support. The build mode
// should be auto-detected at compile time, but it's possible to override it in
// case that the auto-detection fails.
//
// Tracing is a feature that is never compiled by default and it's only used to
// debug AsmJit itself.
//
// #define ASMJIT_DEBUG // Define to enable debug-mode.
// #define ASMJIT_RELEASE // Define to enable release-mode.
// AsmJit Build Backends
// ---------------------
//
// These definitions control which backends to compile. If none of these is
// defined AsmJit will use host architecture by default (for JIT code generation).
//
// #define ASMJIT_BUILD_X86 // Define to enable X86 and X64 code-generation.
// #define ASMJIT_BUILD_ARM // Define to enable ARM32 and ARM64 code-generation.
// #define ASMJIT_BUILD_HOST // Define to enable host instruction set.
// AsmJit Build Features
// ---------------------
//
// Flags can be defined to disable standard features. These are handy especially
// when building AsmJit statically and some features are not needed or unwanted
// (like CodeCompiler).
//
// AsmJit features are enabled by default.
// #define ASMJIT_DISABLE_COMPILER // Disable CodeCompiler (completely).
// #define ASMJIT_DISABLE_LOGGING // Disable logging and formatting (completely).
// #define ASMJIT_DISABLE_TEXT // Disable everything that contains text
// // representation (instructions, errors, ...).
// #define ASMJIT_DISABLE_VALIDATION // Disable Validation (completely).
// Prevent compile-time errors caused by misconfiguration.
#if defined(ASMJIT_DISABLE_TEXT) && !defined(ASMJIT_DISABLE_LOGGING)
# error "[asmjit] ASMJIT_DISABLE_TEXT requires ASMJIT_DISABLE_LOGGING to be defined."
#endif // ASMJIT_DISABLE_TEXT && !ASMJIT_DISABLE_LOGGING
// Detect ASMJIT_DEBUG and ASMJIT_RELEASE if not forced from outside.
#if !defined(ASMJIT_DEBUG) && !defined(ASMJIT_RELEASE)
# if !defined(NDEBUG)
# define ASMJIT_DEBUG
# else
# define ASMJIT_RELEASE
# endif
#endif
// ASMJIT_EMBED implies ASMJIT_STATIC.
#if defined(ASMJIT_EMBED) && !defined(ASMJIT_STATIC)
# define ASMJIT_STATIC
#endif
// ============================================================================
// [asmjit::Build - VERSION]
// ============================================================================
// [@VERSION{@]
#define ASMJIT_VERSION_MAJOR 1
#define ASMJIT_VERSION_MINOR 0
#define ASMJIT_VERSION_PATCH 0
#define ASMJIT_VERSION_STRING "1.0.0"
// [@VERSION}@]
// ============================================================================
// [asmjit::Build - WIN32]
// ============================================================================
// [@WIN32_CRT_NO_DEPRECATE{@]
#if defined(_MSC_VER) && defined(ASMJIT_EXPORTS)
# if !defined(_CRT_SECURE_NO_DEPRECATE)
# define _CRT_SECURE_NO_DEPRECATE
# endif
# if !defined(_CRT_SECURE_NO_WARNINGS)
# define _CRT_SECURE_NO_WARNINGS
# endif
#endif
// [@WIN32_CRT_NO_DEPRECATE}@]
// [@WIN32_LEAN_AND_MEAN{@]
#if (defined(_WIN32) || defined(_WINDOWS)) && !defined(_WINDOWS_)
# if !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# define ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN
# endif
# if !defined(NOMINMAX)
# define NOMINMAX
# define ASMJIT_UNDEF_NOMINMAX
# endif
# include <windows.h>
# if defined(ASMJIT_UNDEF_NOMINMAX)
# undef NOMINMAX
# undef ASMJIT_UNDEF_NOMINMAX
# endif
# if defined(ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN)
# undef WIN32_LEAN_AND_MEAN
# undef ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN
# endif
#endif
// [@WIN32_LEAN_AND_MEAN}@]
// ============================================================================
// [asmjit::Build - OS]
// ============================================================================
// [@OS{@]
#if defined(_WIN32) || defined(_WINDOWS)
#define ASMJIT_OS_WINDOWS (1)
#else
#define ASMJIT_OS_WINDOWS (0)
#endif
#if defined(__APPLE__)
# include <TargetConditionals.h>
# define ASMJIT_OS_MAC (TARGET_OS_MAC)
# define ASMJIT_OS_IOS (TARGET_OS_IPHONE)
#else
# define ASMJIT_OS_MAC (0)
# define ASMJIT_OS_IOS (0)
#endif
#if defined(__ANDROID__)
# define ASMJIT_OS_ANDROID (1)
#else
# define ASMJIT_OS_ANDROID (0)
#endif
#if defined(__linux__) || defined(__ANDROID__)
# define ASMJIT_OS_LINUX (1)
#else
# define ASMJIT_OS_LINUX (0)
#endif
#if defined(__DragonFly__)
# define ASMJIT_OS_DRAGONFLYBSD (1)
#else
# define ASMJIT_OS_DRAGONFLYBSD (0)
#endif
#if defined(__FreeBSD__)
# define ASMJIT_OS_FREEBSD (1)
#else
# define ASMJIT_OS_FREEBSD (0)
#endif
#if defined(__NetBSD__)
# define ASMJIT_OS_NETBSD (1)
#else
# define ASMJIT_OS_NETBSD (0)
#endif
#if defined(__OpenBSD__)
# define ASMJIT_OS_OPENBSD (1)
#else
# define ASMJIT_OS_OPENBSD (0)
#endif
#if defined(__QNXNTO__)
# define ASMJIT_OS_QNX (1)
#else
# define ASMJIT_OS_QNX (0)
#endif
#if defined(__sun)
# define ASMJIT_OS_SOLARIS (1)
#else
# define ASMJIT_OS_SOLARIS (0)
#endif
#if defined(__CYGWIN__)
# define ASMJIT_OS_CYGWIN (1)
#else
# define ASMJIT_OS_CYGWIN (0)
#endif
#define ASMJIT_OS_BSD ( \
ASMJIT_OS_FREEBSD || \
ASMJIT_OS_DRAGONFLYBSD || \
ASMJIT_OS_NETBSD || \
ASMJIT_OS_OPENBSD || \
ASMJIT_OS_MAC)
#define ASMJIT_OS_POSIX (!ASMJIT_OS_WINDOWS)
// [@OS}@]
// ============================================================================
// [asmjit::Build - ARCH]
// ============================================================================
// [@ARCH{@]
// \def ASMJIT_ARCH_ARM32
// True if the target architecture is a 32-bit ARM.
//
// \def ASMJIT_ARCH_ARM64
// True if the target architecture is a 64-bit ARM.
//
// \def ASMJIT_ARCH_X86
// True if the target architecture is a 32-bit X86/IA32
//
// \def ASMJIT_ARCH_X64
// True if the target architecture is a 64-bit X64/AMD64
//
// \def ASMJIT_ARCH_LE
// True if the target architecture is little endian.
//
// \def ASMJIT_ARCH_BE
// True if the target architecture is big endian.
//
// \def ASMJIT_ARCH_64BIT
// True if the target architecture is 64-bit.
#if (defined(_M_X64 ) || defined(__x86_64) || defined(__x86_64__) || \
defined(_M_AMD64) || defined(__amd64 ) || defined(__amd64__ ))
# define ASMJIT_ARCH_X64 1
#else
# define ASMJIT_ARCH_X64 0
#endif
#if (defined(_M_IX86 ) || defined(__X86__ ) || defined(__i386 ) || \
defined(__IA32__) || defined(__I86__ ) || defined(__i386__) || \
defined(__i486__) || defined(__i586__) || defined(__i686__))
# define ASMJIT_ARCH_X86 (!ASMJIT_ARCH_X64)
#else
# define ASMJIT_ARCH_X86 0
#endif
#if defined(__aarch64__)
# define ASMJIT_ARCH_ARM64 1
#else
# define ASMJIT_ARCH_ARM64 0
#endif
#if (defined(_M_ARM ) || defined(__arm ) || defined(__thumb__ ) || \
defined(_M_ARMT ) || defined(__arm__ ) || defined(__thumb2__))
# define ASMJIT_ARCH_ARM32 (!ASMJIT_ARCH_ARM64)
#else
# define ASMJIT_ARCH_ARM32 0
#endif
#define ASMJIT_ARCH_LE ( \
ASMJIT_ARCH_X86 || \
ASMJIT_ARCH_X64 || \
ASMJIT_ARCH_ARM32 || \
ASMJIT_ARCH_ARM64 )
#define ASMJIT_ARCH_BE (!(ASMJIT_ARCH_LE))
#define ASMJIT_ARCH_64BIT (ASMJIT_ARCH_X64 || ASMJIT_ARCH_ARM64)
// [@ARCH}@]
// [@ARCH_UNALIGNED_RW{@]
// \def ASMJIT_ARCH_UNALIGNED_16
// True if the target architecture allows unaligned 16-bit reads and writes.
//
// \def ASMJIT_ARCH_UNALIGNED_32
// True if the target architecture allows unaligned 32-bit reads and writes.
//
// \def ASMJIT_ARCH_UNALIGNED_64
// True if the target architecture allows unaligned 64-bit reads and writes.
#define ASMJIT_ARCH_UNALIGNED_16 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64)
#define ASMJIT_ARCH_UNALIGNED_32 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64)
#define ASMJIT_ARCH_UNALIGNED_64 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64)
// [@ARCH_UNALIGNED_RW}@]
// ============================================================================
// [asmjit::Build - CC]
// ============================================================================
// [@CC{@]
// \def ASMJIT_CC_CLANG
// Non-zero if the detected C++ compiler is CLANG (contains normalized CLANG version).
//
// \def ASMJIT_CC_CODEGEAR
// Non-zero if the detected C++ compiler is CODEGEAR or BORLAND (version not normalized).
//
// \def ASMJIT_CC_INTEL
// Non-zero if the detected C++ compiler is INTEL (version not normalized).
//
// \def ASMJIT_CC_GCC
// Non-zero if the detected C++ compiler is GCC (contains normalized GCC version).
//
// \def ASMJIT_CC_MSC
// Non-zero if the detected C++ compiler is MSC (contains normalized MSC version).
//
// \def ASMJIT_CC_MINGW
// Non-zero if the detected C++ compiler is MINGW32 (set to 32) or MINGW64 (set to 64).
#define ASMJIT_CC_CLANG 0
#define ASMJIT_CC_CODEGEAR 0
#define ASMJIT_CC_GCC 0
#define ASMJIT_CC_INTEL 0
#define ASMJIT_CC_MSC 0
// Intel masquerades as GCC, so check for it first.
#if defined(__INTEL_COMPILER)
# undef ASMJIT_CC_INTEL
# define ASMJIT_CC_INTEL __INTEL_COMPILER
#elif defined(__CODEGEARC__)
# undef ASMJIT_CC_CODEGEAR
# define ASMJIT_CC_CODEGEAR (__CODEGEARC__)
#elif defined(__BORLANDC__)
# undef ASMJIT_CC_CODEGEAR
# define ASMJIT_CC_CODEGEAR (__BORLANDC__)
#elif defined(__clang__) && defined(__clang_minor__)
# undef ASMJIT_CC_CLANG
# define ASMJIT_CC_CLANG (__clang_major__ * 10000000 + __clang_minor__ * 100000 + __clang_patchlevel__)
#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
# undef ASMJIT_CC_GCC
# define ASMJIT_CC_GCC (__GNUC__ * 10000000 + __GNUC_MINOR__ * 100000 + __GNUC_PATCHLEVEL__)
#elif defined(_MSC_VER) && defined(_MSC_FULL_VER)
# undef ASMJIT_CC_MSC
# if _MSC_VER == _MSC_FULL_VER / 10000
# define ASMJIT_CC_MSC (_MSC_VER * 100000 + (_MSC_FULL_VER % 10000))
# else
# define ASMJIT_CC_MSC (_MSC_VER * 100000 + (_MSC_FULL_VER % 100000))
# endif
#else
# error "[asmjit] Unable to detect the C/C++ compiler."
#endif
#if ASMJIT_CC_INTEL && (defined(__GNUC__) || defined(__clang__))
# define ASMJIT_CC_INTEL_COMPAT_MODE 1
# else
# define ASMJIT_CC_INTEL_COMPAT_MODE 0
#endif
#define ASMJIT_CC_CODEGEAR_EQ(x, y) (ASMJIT_CC_CODEGEAR == (((x) << 8) + (y)))
#define ASMJIT_CC_CODEGEAR_GE(x, y) (ASMJIT_CC_CODEGEAR >= (((x) << 8) + (y)))
#define ASMJIT_CC_CLANG_EQ(x, y, z) (ASMJIT_CC_CLANG == ((x) * 10000000 + (y) * 100000 + (z)))
#define ASMJIT_CC_CLANG_GE(x, y, z) (ASMJIT_CC_CLANG >= ((x) * 10000000 + (y) * 100000 + (z)))
#define ASMJIT_CC_GCC_EQ(x, y, z) (ASMJIT_CC_GCC == ((x) * 10000000 + (y) * 100000 + (z)))
#define ASMJIT_CC_GCC_GE(x, y, z) (ASMJIT_CC_GCC >= ((x) * 10000000 + (y) * 100000 + (z)))
#define ASMJIT_CC_INTEL_EQ(x, y) (ASMJIT_CC_INTEL == (((x) * 100) + (y)))
#define ASMJIT_CC_INTEL_GE(x, y) (ASMJIT_CC_INTEL >= (((x) * 100) + (y)))
#define ASMJIT_CC_MSC_EQ(x, y, z) (ASMJIT_CC_MSC == ((x) * 10000000 + (y) * 100000 + (z)))
#define ASMJIT_CC_MSC_GE(x, y, z) (ASMJIT_CC_MSC >= ((x) * 10000000 + (y) * 100000 + (z)))
#if defined(__MINGW64__)
# define ASMJIT_CC_MINGW 64
#elif defined(__MINGW32__)
# define ASMJIT_CC_MINGW 32
#else
# define ASMJIT_CC_MINGW 0
#endif
#if defined(__cplusplus)
# if __cplusplus >= 201103L
# define ASMJIT_CC_CXX_VERSION __cplusplus
# elif defined(__GXX_EXPERIMENTAL_CXX0X__) || ASMJIT_CC_MSC_GE(18, 0, 0) || ASMJIT_CC_INTEL_GE(14, 0)
# define ASMJIT_CC_CXX_VERSION 201103L
# else
# define ASMJIT_CC_CXX_VERSION 199711L
# endif
#endif
#if !defined(ASMJIT_CC_CXX_VERSION)
# define ASMJIT_CC_CXX_VERSION 0
#endif
// [@CC}@]
// [@CC_FEATURES{@]
#if ASMJIT_CC_CLANG
# define ASMJIT_CC_HAS_ATTRIBUTE (1)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (__has_attribute(__aligned__))
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (__has_attribute(__always_inline__))
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (__has_attribute(__noinline__))
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (__has_attribute(__noreturn__))
# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (__has_attribute(__optimize__))
# define ASMJIT_CC_HAS_BUILTIN_ASSUME (__has_builtin(__builtin_assume))
# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (__has_builtin(__builtin_assume_aligned))
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (__has_builtin(__builtin_expect))
# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (__has_builtin(__builtin_unreachable))
# define ASMJIT_CC_HAS_ALIGNAS (__has_extension(__cxx_alignas__))
# define ASMJIT_CC_HAS_ALIGNOF (__has_extension(__cxx_alignof__))
# define ASMJIT_CC_HAS_CONSTEXPR (__has_extension(__cxx_constexpr__))
# define ASMJIT_CC_HAS_DECLTYPE (__has_extension(__cxx_decltype__))
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (__has_extension(__cxx_defaulted_functions__))
# define ASMJIT_CC_HAS_DELETE_FUNCTION (__has_extension(__cxx_deleted_functions__))
# define ASMJIT_CC_HAS_FINAL (__has_extension(__cxx_override_control__))
# define ASMJIT_CC_HAS_INITIALIZER_LIST (__has_extension(__cxx_generalized_initializers__))
# define ASMJIT_CC_HAS_LAMBDA (__has_extension(__cxx_lambdas__))
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (__has_extension(__cxx_unicode_literals__))
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (__has_extension(__cxx_unicode_literals__))
# define ASMJIT_CC_HAS_NOEXCEPT (__has_extension(__cxx_noexcept__))
# define ASMJIT_CC_HAS_NULLPTR (__has_extension(__cxx_nullptr__))
# define ASMJIT_CC_HAS_OVERRIDE (__has_extension(__cxx_override_control__))
# define ASMJIT_CC_HAS_RVALUE (__has_extension(__cxx_rvalue_references__))
# define ASMJIT_CC_HAS_STATIC_ASSERT (__has_extension(__cxx_static_assert__))
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (__has_extension(__cxx_variadic_templates__))
#endif
#if ASMJIT_CC_CODEGEAR
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (ASMJIT_CC_CODEGEAR >= 0x0610)
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (0)
# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (0)
# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (ASMJIT_CC_CODEGEAR >= 0x0610)
# define ASMJIT_CC_HAS_ALIGNAS (0)
# define ASMJIT_CC_HAS_ALIGNOF (0)
# define ASMJIT_CC_HAS_CONSTEXPR (0)
# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_CODEGEAR >= 0x0610)
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (0)
# define ASMJIT_CC_HAS_DELETE_FUNCTION (0)
# define ASMJIT_CC_HAS_FINAL (0)
# define ASMJIT_CC_HAS_INITIALIZER_LIST (0)
# define ASMJIT_CC_HAS_LAMBDA (0)
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (0)
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (0)
# define ASMJIT_CC_HAS_NOEXCEPT (0)
# define ASMJIT_CC_HAS_NULLPTR (0)
# define ASMJIT_CC_HAS_OVERRIDE (0)
# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_CODEGEAR >= 0x0610)
# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_CODEGEAR >= 0x0610)
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (0)
#endif
#if ASMJIT_CC_GCC
# define ASMJIT_CC_HAS_ATTRIBUTE (1)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (ASMJIT_CC_GCC_GE(2, 7, 0))
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (ASMJIT_CC_GCC_GE(4, 4, 0) && !ASMJIT_CC_MINGW)
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (ASMJIT_CC_GCC_GE(3, 4, 0) && !ASMJIT_CC_MINGW)
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (ASMJIT_CC_GCC_GE(2, 5, 0))
# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (ASMJIT_CC_GCC_GE(4, 4, 0))
# define ASMJIT_CC_HAS_BUILTIN_ASSUME (0)
# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (ASMJIT_CC_GCC_GE(4, 7, 0))
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (1)
# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_GCC_GE(4, 7, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_GCC_GE(4, 7, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
#endif
#if ASMJIT_CC_INTEL
# define ASMJIT_CC_HAS_ATTRIBUTE (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (ASMJIT_CC_INTEL_COMPAT_MODE == 0)
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (ASMJIT_CC_INTEL_COMPAT_MODE == 0)
# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (ASMJIT_CC_INTEL_COMPAT_MODE == 0)
# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (ASMJIT_CC_INTEL_COMPAT_MODE == 0)
# define ASMJIT_CC_HAS_ASSUME (1)
# define ASMJIT_CC_HAS_ASSUME_ALIGNED (1)
# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_INTEL >= 1500)
# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_INTEL >= 1500)
# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_INTEL >= 1400)
# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_INTEL >= 1200)
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_INTEL >= 1200)
# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_INTEL >= 1200)
# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_INTEL >= 1400)
# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_INTEL >= 1400)
# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_INTEL >= 1200)
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_INTEL >= 1400 || (ASMJIT_CC_INTEL_COMPAT_MODE > 0 && ASMJIT_CC_INTEL >= 1206))
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_INTEL >= 1400 || (ASMJIT_CC_INTEL_COMPAT_MODE > 0 && ASMJIT_CC_INTEL >= 1206))
# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_INTEL >= 1400)
# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_INTEL >= 1206)
# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_INTEL >= 1400)
# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_INTEL >= 1110)
# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_INTEL >= 1110)
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_INTEL >= 1206)
#endif
#if ASMJIT_CC_MSC
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (1)
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (1)
# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (1)
# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (1)
# define ASMJIT_CC_HAS_ASSUME (1)
# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0)
# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_MSC_GE(16, 0, 0))
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_MSC_GE(18, 0, 0))
# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_MSC_GE(18, 0, 0))
# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_MSC_GE(14, 0, 0))
# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_MSC_GE(18, 0, 0))
# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_MSC_GE(16, 0, 0))
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
# if defined(_NATIVE_WCHAR_T_DEFINED)
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
# else
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (0)
# endif
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_MSC_GE(16, 0, 0))
# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_MSC_GE(14, 0, 0))
# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_MSC_GE(16, 0, 0))
# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_MSC_GE(16, 0, 0))
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_MSC_GE(18, 0, 0))
#endif
// Fixup some vendor specific keywords.
#if !defined(ASMJIT_CC_HAS_ASSUME)
# define ASMJIT_CC_HAS_ASSUME (0)
#endif
#if !defined(ASMJIT_CC_HAS_ASSUME_ALIGNED)
# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0)
#endif
// Fixup compilers that don't support '__attribute__'.
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE)
# define ASMJIT_CC_HAS_ATTRIBUTE (0)
#endif
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (0)
#endif
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (0)
#endif
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE)
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (0)
#endif
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_NORETURN)
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (0)
#endif
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE)
# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (0)
#endif
// Fixup compilers that don't support '__builtin?'.
#if !defined(ASMJIT_CC_HAS_BUILTIN_ASSUME)
# define ASMJIT_CC_HAS_BUILTIN_ASSUME (0)
#endif
#if !defined(ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED)
# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (0)
#endif
#if !defined(ASMJIT_CC_HAS_BUILTIN_EXPECT)
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (0)
#endif
#if !defined(ASMJIT_CC_HAS_BUILTIN_UNREACHABLE)
# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (0)
#endif
// Fixup compilers that don't support 'declspec'.
#if !defined(ASMJIT_CC_HAS_DECLSPEC_ALIGN)
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (0)
#endif
#if !defined(ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE)
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (0)
#endif
#if !defined(ASMJIT_CC_HAS_DECLSPEC_NOINLINE)
# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (0)
#endif
#if !defined(ASMJIT_CC_HAS_DECLSPEC_NORETURN)
# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (0)
#endif
// [@CC_FEATURES}@]
// [@CC_API{@]
// \def ASMJIT_API
// The decorated function is asmjit API and should be exported.
#if !defined(ASMJIT_API)
# if defined(ASMJIT_STATIC)
# define ASMJIT_API
# elif ASMJIT_OS_WINDOWS
# if (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && !ASMJIT_CC_MINGW
# if defined(ASMJIT_EXPORTS)
# define ASMJIT_API __attribute__((__dllexport__))
# else
# define ASMJIT_API __attribute__((__dllimport__))
# endif
# else
# if defined(ASMJIT_EXPORTS)
# define ASMJIT_API __declspec(dllexport)
# else
# define ASMJIT_API __declspec(dllimport)
# endif
# endif
# else
# if ASMJIT_CC_CLANG || ASMJIT_CC_GCC_GE(4, 0, 0) || ASMJIT_CC_INTEL
# define ASMJIT_API __attribute__((__visibility__("default")))
# endif
# endif
#endif
// [@CC_API}@]
// [@CC_VARAPI{@]
// \def ASMJIT_VARAPI
// The decorated variable is part of asmjit API and is exported.
#if !defined(ASMJIT_VARAPI)
# define ASMJIT_VARAPI extern ASMJIT_API
#endif
// [@CC_VARAPI}@]
// [@CC_VIRTAPI{@]
// \def ASMJIT_VIRTAPI
// The decorated class has a virtual table and is part of asmjit API.
//
// This is basically a workaround. When using MSVC and marking class as DLL
// export everything gets exported, which is unwanted in most projects. MSVC
// automatically exports typeinfo and vtable if at least one symbol of the
// class is exported. However, GCC has some strange behavior that even if
// one or more symbol is exported it doesn't export typeinfo unless the
// class itself is decorated with "visibility(default)" (i.e. asmjit_API).
#if (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && !ASMJIT_OS_WINDOWS
# define ASMJIT_VIRTAPI ASMJIT_API
#else
# define ASMJIT_VIRTAPI
#endif
// [@CC_VIRTAPI}@]
// [@CC_INLINE{@]
// \def ASMJIT_INLINE
// Always inline the decorated function.
#if ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE
# define ASMJIT_INLINE inline __attribute__((__always_inline__))
#elif ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE
# define ASMJIT_INLINE __forceinline
#else
# define ASMJIT_INLINE inline
#endif
// [@CC_INLINE}@]
// [@CC_NOINLINE{@]
// \def ASMJIT_NOINLINE
// Never inline the decorated function.
#if ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE
# define ASMJIT_NOINLINE __attribute__((__noinline__))
#elif ASMJIT_CC_HAS_DECLSPEC_NOINLINE
# define ASMJIT_NOINLINE __declspec(noinline)
#else
# define ASMJIT_NOINLINE
#endif
// [@CC_NOINLINE}@]
// [@CC_NORETURN{@]
// \def ASMJIT_NORETURN
// The decorated function never returns (exit, assertion failure, etc...).
#if ASMJIT_CC_HAS_ATTRIBUTE_NORETURN
# define ASMJIT_NORETURN __attribute__((__noreturn__))
#elif ASMJIT_CC_HAS_DECLSPEC_NORETURN
# define ASMJIT_NORETURN __declspec(noreturn)
#else
# define ASMJIT_NORETURN
#endif
// [@CC_NORETURN}@]
// [@CC_CDECL{@]
// \def ASMJIT_CDECL
// Standard C function calling convention decorator (__cdecl).
#if ASMJIT_ARCH_X86
# if ASMJIT_CC_HAS_ATTRIBUTE
# define ASMJIT_CDECL __attribute__((__cdecl__))
# else
# define ASMJIT_CDECL __cdecl
# endif
#else
# define ASMJIT_CDECL
#endif
// [@CC_CDECL}@]
// [@CC_STDCALL{@]
// \def ASMJIT_STDCALL
// StdCall function calling convention decorator (__stdcall).
#if ASMJIT_ARCH_X86
# if ASMJIT_CC_HAS_ATTRIBUTE
# define ASMJIT_STDCALL __attribute__((__stdcall__))
# else
# define ASMJIT_STDCALL __stdcall
# endif
#else
# define ASMJIT_STDCALL
#endif
// [@CC_STDCALL}@]
// [@CC_FASTCALL{@]
// \def ASMJIT_FASTCALL
// FastCall function calling convention decorator (__fastcall).
#if ASMJIT_ARCH_X86
# if ASMJIT_CC_HAS_ATTRIBUTE
# define ASMJIT_FASTCALL __attribute__((__fastcall__))
# else
# define ASMJIT_FASTCALL __fastcall
# endif
#else
# define ASMJIT_FASTCALL
#endif
// [@CC_FASTCALL}@]
// [@CC_REGPARM{@]
// \def ASMJIT_REGPARM(n)
// A custom calling convention which passes n arguments in registers.
#if ASMJIT_ARCH_X86 && ASMJIT_CC_HAS_ATTRIBUTE
# define ASMJIT_REGPARM(n) __attribute__((__regparm__(n)))
#else
# define ASMJIT_REGPARM(n)
#endif
// [@CC_REGPARM}@]
// [@CC_NOEXCEPT{@]
// \def ASMJIT_NOEXCEPT
// The decorated function never throws an exception (noexcept).
#if ASMJIT_CC_HAS_NOEXCEPT
# define ASMJIT_NOEXCEPT noexcept
#else
# define ASMJIT_NOEXCEPT
#endif
// [@CC_NOEXCEPT}@]
// [@CC_NOP{@]
// \def ASMJIT_NOP
// No operation.
#if !defined(ASMJIT_NOP)
# define ASMJIT_NOP ((void)0)
#endif
// [@CC_NOP}@]
// [@CC_ASSUME{@]
// \def ASMJIT_ASSUME(exp)
// Assume that the expression exp is always true.
#if ASMJIT_CC_HAS_ASSUME
# define ASMJIT_ASSUME(exp) __assume(exp)
#elif ASMJIT_CC_HAS_BUILTIN_ASSUME
# define ASMJIT_ASSUME(exp) __builtin_assume(exp)
#elif ASMJIT_CC_HAS_BUILTIN_UNREACHABLE
# define ASMJIT_ASSUME(exp) do { if (!(exp)) __builtin_unreachable(); } while (0)
#else
# define ASMJIT_ASSUME(exp) ((void)0)
#endif
// [@CC_ASSUME}@]
// [@CC_ASSUME_ALIGNED{@]
// \def ASMJIT_ASSUME_ALIGNED(p, alignment)
// Assume that the pointer 'p' is aligned to at least 'alignment' bytes.
#if ASMJIT_CC_HAS_ASSUME_ALIGNED
# define ASMJIT_ASSUME_ALIGNED(p, alignment) __assume_aligned(p, alignment)
#elif ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED
# define ASMJIT_ASSUME_ALIGNED(p, alignment) p = __builtin_assume_aligned(p, alignment)
#else
# define ASMJIT_ASSUME_ALIGNED(p, alignment) ((void)0)
#endif
// [@CC_ASSUME_ALIGNED}@]
// [@CC_EXPECT{@]
// \def ASMJIT_LIKELY(exp)
// Expression exp is likely to be true.
//
// \def ASMJIT_UNLIKELY(exp)
// Expression exp is likely to be false.
#if ASMJIT_CC_HAS_BUILTIN_EXPECT
# define ASMJIT_LIKELY(exp) __builtin_expect(!!(exp), 1)
# define ASMJIT_UNLIKELY(exp) __builtin_expect(!!(exp), 0)
#else
# define ASMJIT_LIKELY(exp) (exp)
# define ASMJIT_UNLIKELY(exp) (exp)
#endif
// [@CC_EXPECT}@]
// [@CC_FALLTHROUGH{@]
// \def ASMJIT_FALLTHROUGH
// The code falls through annotation (switch / case).
#if ASMJIT_CC_CLANG && __cplusplus >= 201103L
# define ASMJIT_FALLTHROUGH [[clang::fallthrough]]
#else
# define ASMJIT_FALLTHROUGH (void)0
#endif
// [@CC_FALLTHROUGH}@]
// [@CC_UNUSED{@]
// \def ASMJIT_UNUSED(x)
// Mark a variable x as unused.
#define ASMJIT_UNUSED(x) (void)(x)
// [@CC_UNUSED}@]
// [@CC_OFFSET_OF{@]
// \def ASMJIT_OFFSET_OF(x, y).
// Get the offset of a member y of a struct x at compile-time.
#define ASMJIT_OFFSET_OF(x, y) ((int)(intptr_t)((const char*)&((const x*)0x1)->y) - 1)
// [@CC_OFFSET_OF}@]
// [@CC_ARRAY_SIZE{@]
// \def ASMJIT_ARRAY_SIZE(x)
// Get the array size of x at compile-time.
#define ASMJIT_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
// [@CC_ARRAY_SIZE}@]
// ============================================================================
// [asmjit::Build - STDTYPES]
// ============================================================================
// [@STDTYPES{@]
#if defined(__MINGW32__) || defined(__MINGW64__)
# include <sys/types.h>
#endif
#if defined(_MSC_VER) && (_MSC_VER < 1600)
# include <limits.h>
# if !defined(ASMJIT_SUPPRESS_STD_TYPES)
# if (_MSC_VER < 1300)
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed __int64 int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned __int64 uint64_t;
# else
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
# endif
# endif
#else
# include <stdint.h>
# include <limits.h>
#endif
// [@STDTYPES}@]
// ============================================================================
// [asmjit::Build - Dependencies]
// ============================================================================
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <new>
#if ASMJIT_OS_POSIX
# include <pthread.h>
#endif // ASMJIT_OS_POSIX
// ============================================================================
// [asmjit::Build - Additional]
// ============================================================================
// Build host architecture if no architecture is selected.
#if !defined(ASMJIT_BUILD_HOST) && \
!defined(ASMJIT_BUILD_X86) && \
!defined(ASMJIT_BUILD_ARM)
# define ASMJIT_BUILD_HOST
#endif
// Detect host architecture if building only for host.
#if defined(ASMJIT_BUILD_HOST)
# if (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && !defined(ASMJIT_BUILD_X86)
# define ASMJIT_BUILD_X86
# endif // ASMJIT_ARCH_X86
#endif // ASMJIT_BUILD_HOST
#if ASMJIT_CC_MSC
# define ASMJIT_UINT64_C(x) x##ui64
#else
# define ASMJIT_UINT64_C(x) x##ull
#endif
#if ASMJIT_ARCH_LE
# define ASMJIT_PACK32_4x8(A, B, C, D) ((A) + ((B) << 8) + ((C) << 16) + ((D) << 24))
#else
# define ASMJIT_PACK32_4x8(A, B, C, D) ((D) + ((C) << 8) + ((B) << 16) + ((A) << 24))
#endif
// Internal macros that are only used when building AsmJit itself.
#if defined(ASMJIT_EXPORTS)
# if !defined(ASMJIT_DEBUG) && ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE
# define ASMJIT_FAVOR_SIZE __attribute__((__optimize__("Os")))
# else
# define ASMJIT_FAVOR_SIZE
# endif
#endif // ASMJIT_EXPORTS
// ============================================================================
// [asmjit::Build - Test]
// ============================================================================
// Include a unit testing package if this is a `asmjit_test` build.
#if defined(ASMJIT_TEST)
# include "../../test/broken.h"
#endif // ASMJIT_TEST
// [Guard]
#endif // _ASMJIT_BUILD_H

View File

@ -1,34 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_H
#define _ASMJIT_BASE_H
// [Dependencies]
#include "./base/arch.h"
#include "./base/assembler.h"
#include "./base/codebuilder.h"
#include "./base/codecompiler.h"
#include "./base/codeemitter.h"
#include "./base/codeholder.h"
#include "./base/constpool.h"
#include "./base/cpuinfo.h"
#include "./base/func.h"
#include "./base/globals.h"
#include "./base/inst.h"
#include "./base/logging.h"
#include "./base/operand.h"
#include "./base/osutils.h"
#include "./base/runtime.h"
#include "./base/simdtypes.h"
#include "./base/string.h"
#include "./base/utils.h"
#include "./base/vmem.h"
#include "./base/zone.h"
// [Guard]
#endif // _ASMJIT_BASE_H

View File

@ -1,161 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies]
#include "../base/arch.h"
#if defined(ASMJIT_BUILD_X86)
#include "../x86/x86operand.h"
#endif // ASMJIT_BUILD_X86
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::ArchInfo]
// ============================================================================
static const uint32_t archInfoTable[] = {
// <-------------+---------------------+-----------------------+-------+
// | Type | SubType | GPInfo|
// <-------------+---------------------+-----------------------+-------+
ASMJIT_PACK32_4x8(ArchInfo::kTypeNone , ArchInfo::kSubTypeNone, 0, 0),
ASMJIT_PACK32_4x8(ArchInfo::kTypeX86 , ArchInfo::kSubTypeNone, 4, 8),
ASMJIT_PACK32_4x8(ArchInfo::kTypeX64 , ArchInfo::kSubTypeNone, 8, 16),
ASMJIT_PACK32_4x8(ArchInfo::kTypeX32 , ArchInfo::kSubTypeNone, 8, 16),
ASMJIT_PACK32_4x8(ArchInfo::kTypeA32 , ArchInfo::kSubTypeNone, 4, 16),
ASMJIT_PACK32_4x8(ArchInfo::kTypeA64 , ArchInfo::kSubTypeNone, 8, 32)
};
ASMJIT_FAVOR_SIZE void ArchInfo::init(uint32_t type, uint32_t subType) noexcept {
uint32_t index = type < ASMJIT_ARRAY_SIZE(archInfoTable) ? type : uint32_t(0);
// Make sure the `archInfoTable` array is correctly indexed.
_signature = archInfoTable[index];
ASMJIT_ASSERT(_type == index);
// Even if the architecture is not known we setup its type and sub-type,
// however, such architecture is not really useful.
_type = type;
_subType = subType;
}
// ============================================================================
// [asmjit::ArchUtils]
// ============================================================================
ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegInfo(uint32_t archType, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept {
uint32_t typeId = typeIdInOut;
// Zero the signature so it's clear in case that typeId is not invalid.
regInfo._signature = 0;
#if defined(ASMJIT_BUILD_X86)
if (ArchInfo::isX86Family(archType)) {
// Passed RegType instead of TypeId?
if (typeId <= Reg::kRegMax)
typeId = x86OpData.archRegs.regTypeToTypeId[typeId];
if (ASMJIT_UNLIKELY(!TypeId::isValid(typeId)))
return DebugUtils::errored(kErrorInvalidTypeId);
// First normalize architecture dependent types.
if (TypeId::isAbstract(typeId)) {
if (typeId == TypeId::kIntPtr)
typeId = (archType == ArchInfo::kTypeX86) ? TypeId::kI32 : TypeId::kI64;
else
typeId = (archType == ArchInfo::kTypeX86) ? TypeId::kU32 : TypeId::kU64;
}
// Type size helps to construct all kinds of registers. If the size is zero
// then the TypeId is invalid.
uint32_t size = TypeId::sizeOf(typeId);
if (ASMJIT_UNLIKELY(!size))
return DebugUtils::errored(kErrorInvalidTypeId);
if (ASMJIT_UNLIKELY(typeId == TypeId::kF80))
return DebugUtils::errored(kErrorInvalidUseOfF80);
uint32_t regType = 0;
switch (typeId) {
case TypeId::kI8:
case TypeId::kU8:
regType = X86Reg::kRegGpbLo;
break;
case TypeId::kI16:
case TypeId::kU16:
regType = X86Reg::kRegGpw;
break;
case TypeId::kI32:
case TypeId::kU32:
regType = X86Reg::kRegGpd;
break;
case TypeId::kI64:
case TypeId::kU64:
if (archType == ArchInfo::kTypeX86)
return DebugUtils::errored(kErrorInvalidUseOfGpq);
regType = X86Reg::kRegGpq;
break;
// F32 and F64 are always promoted to use vector registers.
case TypeId::kF32:
typeId = TypeId::kF32x1;
regType = X86Reg::kRegXmm;
break;
case TypeId::kF64:
typeId = TypeId::kF64x1;
regType = X86Reg::kRegXmm;
break;
// Mask registers {k}.
case TypeId::kMask8:
case TypeId::kMask16:
case TypeId::kMask32:
case TypeId::kMask64:
regType = X86Reg::kRegK;
break;
// MMX registers.
case TypeId::kMmx32:
case TypeId::kMmx64:
regType = X86Reg::kRegMm;
break;
// XMM|YMM|ZMM registers.
default:
if (size <= 16)
regType = X86Reg::kRegXmm;
else if (size == 32)
regType = X86Reg::kRegYmm;
else
regType = X86Reg::kRegZmm;
break;
}
typeIdInOut = typeId;
regInfo._signature = x86OpData.archRegs.regInfo[regType].getSignature();
return kErrorOk;
}
#endif // ASMJIT_BUILD_X86
return DebugUtils::errored(kErrorInvalidArch);
}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"

View File

@ -1,199 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_ARCH_H
#define _ASMJIT_BASE_ARCH_H
// [Dependencies]
#include "../base/globals.h"
#include "../base/operand.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [asmjit::ArchInfo]
// ============================================================================
class ArchInfo {
public:
//! Architecture type.
ASMJIT_ENUM(Type) {
kTypeNone = 0, //!< No/Unknown architecture.
// X86 architectures.
kTypeX86 = 1, //!< X86 architecture (32-bit).
kTypeX64 = 2, //!< X64 architecture (64-bit) (AMD64).
kTypeX32 = 3, //!< X32 architecture (DEAD-END).
// ARM architectures.
kTypeA32 = 4, //!< ARM 32-bit architecture (AArch32/ARM/THUMB).
kTypeA64 = 5, //!< ARM 64-bit architecture (AArch64).
//! Architecture detected at compile-time (architecture of the host).
kTypeHost = ASMJIT_ARCH_X86 ? kTypeX86 :
ASMJIT_ARCH_X64 ? kTypeX64 :
ASMJIT_ARCH_ARM32 ? kTypeA32 :
ASMJIT_ARCH_ARM64 ? kTypeA64 : kTypeNone
};
//! Architecture sub-type or execution mode.
ASMJIT_ENUM(SubType) {
kSubTypeNone = 0, //!< Default mode (or no specific mode).
// X86 sub-types.
kSubTypeX86_AVX = 1, //!< Code generation uses AVX by default (VEC instructions).
kSubTypeX86_AVX2 = 2, //!< Code generation uses AVX2 by default (VEC instructions).
kSubTypeX86_AVX512 = 3, //!< Code generation uses AVX-512F by default (+32 vector regs).
kSubTypeX86_AVX512VL = 4, //!< Code generation uses AVX-512F-VL by default (+VL extensions).
// ARM sub-types.
kSubTypeA32_Thumb = 8, //!< THUMB|THUMB2 sub-type (only ARM in 32-bit mode).
#if (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX512VL__)
kSubTypeHost = kSubTypeX86_AVX512VL
#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX512F__)
kSubTypeHost = kSubTypeX86_AVX512
#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX2__)
kSubTypeHost = kSubTypeX86_AVX2
#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX__)
kSubTypeHost = kSubTypeX86_AVX
#elif (ASMJIT_ARCH_ARM32) && (defined(_M_ARMT) || defined(__thumb__) || defined(__thumb2__))
kSubTypeHost = kSubTypeA32_Thumb
#else
kSubTypeHost = 0
#endif
};
// --------------------------------------------------------------------------
// [Utilities]
// --------------------------------------------------------------------------
static ASMJIT_INLINE bool isX86Family(uint32_t archType) noexcept { return archType >= kTypeX86 && archType <= kTypeX32; }
static ASMJIT_INLINE bool isArmFamily(uint32_t archType) noexcept { return archType >= kTypeA32 && archType <= kTypeA64; }
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE ArchInfo() noexcept : _signature(0) {}
ASMJIT_INLINE ArchInfo(const ArchInfo& other) noexcept : _signature(other._signature) {}
explicit ASMJIT_INLINE ArchInfo(uint32_t type, uint32_t subType = kSubTypeNone) noexcept { init(type, subType); }
ASMJIT_INLINE static ArchInfo host() noexcept { return ArchInfo(kTypeHost, kSubTypeHost); }
// --------------------------------------------------------------------------
// [Init / Reset]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isInitialized() const noexcept { return _type != kTypeNone; }
ASMJIT_API void init(uint32_t type, uint32_t subType = kSubTypeNone) noexcept;
ASMJIT_INLINE void reset() noexcept { _signature = 0; }
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get if the architecture is 32-bit.
ASMJIT_INLINE bool is32Bit() const noexcept { return _gpSize == 4; }
//! Get if the architecture is 64-bit.
ASMJIT_INLINE bool is64Bit() const noexcept { return _gpSize == 8; }
//! Get architecture type, see \ref Type.
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
//! Get architecture sub-type, see \ref SubType.
//!
//! X86 & X64
//! ---------
//!
//! Architecture subtype describe the highest instruction-set level that can
//! be used.
//!
//! ARM32
//! -----
//!
//! Architecture mode means the instruction encoding to be used when generating
//! machine code, thus mode can be used to force generation of THUMB and THUMB2
//! encoding or regular ARM encoding.
//!
//! ARM64
//! -----
//!
//! No meaning yet.
ASMJIT_INLINE uint32_t getSubType() const noexcept { return _subType; }
//! Get if the architecture is X86, X64, or X32.
ASMJIT_INLINE bool isX86Family() const noexcept { return isX86Family(_type); }
//! Get if the architecture is ARM32 or ARM64.
ASMJIT_INLINE bool isArmFamily() const noexcept { return isArmFamily(_type); }
//! Get a size of a general-purpose register.
ASMJIT_INLINE uint32_t getGpSize() const noexcept { return _gpSize; }
//! Get number of general-purpose registers.
ASMJIT_INLINE uint32_t getGpCount() const noexcept { return _gpCount; }
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
ASMJIT_INLINE const ArchInfo& operator=(const ArchInfo& other) noexcept { _signature = other._signature; return *this; }
ASMJIT_INLINE bool operator==(const ArchInfo& other) const noexcept { return _signature == other._signature; }
ASMJIT_INLINE bool operator!=(const ArchInfo& other) const noexcept { return _signature != other._signature; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
union {
struct {
uint8_t _type; //!< Architecture type.
uint8_t _subType; //!< Architecture sub-type.
uint8_t _gpSize; //!< Default size of a general purpose register.
uint8_t _gpCount; //!< Count of all general purpose registers.
};
uint32_t _signature; //!< Architecture signature (32-bit int).
};
};
// ============================================================================
// [asmjit::ArchRegs]
// ============================================================================
//! Information about all architecture registers.
struct ArchRegs {
//! Register information and signatures indexed by \ref Reg::Type.
RegInfo regInfo[Reg::kRegMax + 1];
//! Count (maximum) of registers per \ref Reg::Type.
uint8_t regCount[Reg::kRegMax + 1];
//! Converts RegType to TypeId, see \ref TypeId::Id.
uint8_t regTypeToTypeId[Reg::kRegMax + 1];
};
// ============================================================================
// [asmjit::ArchUtils]
// ============================================================================
struct ArchUtils {
ASMJIT_API static Error typeIdToRegInfo(uint32_t archType, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_ARCH_H

View File

@ -1,447 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies]
#include "../base/assembler.h"
#include "../base/constpool.h"
#include "../base/utils.h"
#include "../base/vmem.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::Assembler - Construction / Destruction]
// ============================================================================
Assembler::Assembler() noexcept
: CodeEmitter(kTypeAssembler),
_section(nullptr),
_bufferData(nullptr),
_bufferEnd(nullptr),
_bufferPtr(nullptr),
_op4(),
_op5() {}
Assembler::~Assembler() noexcept {
if (_code) sync();
}
// ============================================================================
// [asmjit::Assembler - Events]
// ============================================================================
Error Assembler::onAttach(CodeHolder* code) noexcept {
// Attach to the end of the .text section.
_section = code->_sections[0];
uint8_t* p = _section->_buffer._data;
_bufferData = p;
_bufferEnd = p + _section->_buffer._capacity;
_bufferPtr = p + _section->_buffer._length;
_op4.reset();
_op5.reset();
return Base::onAttach(code);
}
Error Assembler::onDetach(CodeHolder* code) noexcept {
_section = nullptr;
_bufferData = nullptr;
_bufferEnd = nullptr;
_bufferPtr = nullptr;
_op4.reset();
_op5.reset();
return Base::onDetach(code);
}
// ============================================================================
// [asmjit::Assembler - Code-Generation]
// ============================================================================
Error Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
_op4 = o4;
_op5 = o5;
_options |= kOptionOp4Op5Used;
return _emit(instId, o0, o1, o2, o3);
}
Error Assembler::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
const Operand_* op = opArray;
switch (opCount) {
case 0: return _emit(instId, _none, _none, _none, _none);
case 1: return _emit(instId, op[0], _none, _none, _none);
case 2: return _emit(instId, op[0], op[1], _none, _none);
case 3: return _emit(instId, op[0], op[1], op[2], _none);
case 4: return _emit(instId, op[0], op[1], op[2], op[3]);
case 5:
_op4 = op[4];
_op5.reset();
_options |= kOptionOp4Op5Used;
return _emit(instId, op[0], op[1], op[2], op[3]);
case 6:
_op4 = op[4];
_op5 = op[5];
_options |= kOptionOp4Op5Used;
return _emit(instId, op[0], op[1], op[2], op[3]);
default:
return DebugUtils::errored(kErrorInvalidArgument);
}
}
// ============================================================================
// [asmjit::Assembler - Sync]
// ============================================================================
void Assembler::sync() noexcept {
ASMJIT_ASSERT(_code != nullptr); // Only called by CodeHolder, so we must be attached.
ASMJIT_ASSERT(_section != nullptr); // One section must always be active, no matter what.
ASMJIT_ASSERT(_bufferData == _section->_buffer._data); // `_bufferStart` is a shortcut to `_section->buffer.data`.
// Update only if the current offset is greater than the section length.
size_t offset = (size_t)(_bufferPtr - _bufferData);
if (_section->getBuffer().getLength() < offset)
_section->_buffer._length = offset;
}
// ============================================================================
// [asmjit::Assembler - Code-Buffer]
// ============================================================================
Error Assembler::setOffset(size_t offset) {
if (_lastError) return _lastError;
size_t length = std::max(_section->getBuffer().getLength(), getOffset());
if (ASMJIT_UNLIKELY(offset > length))
return setLastError(DebugUtils::errored(kErrorInvalidArgument));
// If the `Assembler` generated any code the `_bufferPtr` may be higher than
// the section length stored in `CodeHolder` as it doesn't update it each
// time it generates machine code. This is the same as calling `sync()`.
if (_section->_buffer._length < length)
_section->_buffer._length = length;
_bufferPtr = _bufferData + offset;
return kErrorOk;
}
// ============================================================================
// [asmjit::Assembler - Comment]
// ============================================================================
Error Assembler::comment(const char* s, size_t len) {
if (_lastError) return _lastError;
#if !defined(ASMJIT_DISABLE_LOGGING)
if (_globalOptions & kOptionLoggingEnabled) {
Logger* logger = _code->getLogger();
logger->log(s, len);
logger->log("\n", 1);
return kErrorOk;
}
#else
ASMJIT_UNUSED(s);
ASMJIT_UNUSED(len);
#endif
return kErrorOk;
}
// ============================================================================
// [asmjit::Assembler - Building Blocks]
// ============================================================================
Label Assembler::newLabel() {
uint32_t id = 0;
if (!_lastError) {
ASMJIT_ASSERT(_code != nullptr);
Error err = _code->newLabelId(id);
if (ASMJIT_UNLIKELY(err)) setLastError(err);
}
return Label(id);
}
Label Assembler::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) {
uint32_t id = 0;
if (!_lastError) {
ASMJIT_ASSERT(_code != nullptr);
Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId);
if (ASMJIT_UNLIKELY(err)) setLastError(err);
}
return Label(id);
}
Error Assembler::bind(const Label& label) {
if (_lastError) return _lastError;
ASMJIT_ASSERT(_code != nullptr);
LabelEntry* le = _code->getLabelEntry(label);
if (ASMJIT_UNLIKELY(!le))
return setLastError(DebugUtils::errored(kErrorInvalidLabel));
// Label can be bound only once.
if (ASMJIT_UNLIKELY(le->isBound()))
return setLastError(DebugUtils::errored(kErrorLabelAlreadyBound));
#if !defined(ASMJIT_DISABLE_LOGGING)
if (_globalOptions & kOptionLoggingEnabled) {
StringBuilderTmp<256> sb;
if (le->hasName())
sb.setFormat("%s:", le->getName());
else
sb.setFormat("L%u:", Operand::unpackId(label.getId()));
size_t binSize = 0;
if (!_code->_logger->hasOption(Logger::kOptionBinaryForm))
binSize = Globals::kInvalidIndex;
Logging::formatLine(sb, nullptr, binSize, 0, 0, getInlineComment());
_code->_logger->log(sb.getData(), sb.getLength());
}
#endif // !ASMJIT_DISABLE_LOGGING
Error err = kErrorOk;
size_t pos = getOffset();
LabelLink* link = le->_links;
LabelLink* prev = nullptr;
while (link) {
intptr_t offset = link->offset;
uint32_t relocId = link->relocId;
if (relocId != RelocEntry::kInvalidId) {
// Adjust relocation data.
RelocEntry* re = _code->_relocations[relocId];
re->_data += static_cast<uint64_t>(pos);
}
else {
// Not using relocId, this means that we are overwriting a real
// displacement in the CodeBuffer.
int32_t patchedValue = static_cast<int32_t>(
static_cast<intptr_t>(pos) - offset + link->rel);
// Size of the value we are going to patch. Only BYTE/DWORD is allowed.
uint32_t size = _bufferData[offset];
if (size == 4)
Utils::writeI32u(_bufferData + offset, static_cast<int32_t>(patchedValue));
else if (size == 1 && Utils::isInt8(patchedValue))
_bufferData[offset] = static_cast<uint8_t>(patchedValue & 0xFF);
else
err = DebugUtils::errored(kErrorInvalidDisplacement);
}
prev = link->prev;
_code->_unresolvedLabelsCount--;
_code->_baseHeap.release(link, sizeof(LabelLink));
link = prev;
}
// Set as bound.
le->_sectionId = _section->getId();
le->_offset = pos;
le->_links = nullptr;
resetInlineComment();
if (err != kErrorOk)
return setLastError(err);
return kErrorOk;
}
Error Assembler::embed(const void* data, uint32_t size) {
if (_lastError) return _lastError;
if (getRemainingSpace() < size) {
Error err = _code->growBuffer(&_section->_buffer, size);
if (ASMJIT_UNLIKELY(err != kErrorOk)) return setLastError(err);
}
::memcpy(_bufferPtr, data, size);
_bufferPtr += size;
#if !defined(ASMJIT_DISABLE_LOGGING)
if (_globalOptions & kOptionLoggingEnabled)
_code->_logger->logBinary(data, size);
#endif // !ASMJIT_DISABLE_LOGGING
return kErrorOk;
}
Error Assembler::embedLabel(const Label& label) {
if (_lastError) return _lastError;
ASMJIT_ASSERT(_code != nullptr);
RelocEntry* re;
LabelEntry* le = _code->getLabelEntry(label);
if (ASMJIT_UNLIKELY(!le))
return setLastError(DebugUtils::errored(kErrorInvalidLabel));
Error err;
uint32_t gpSize = getGpSize();
if (getRemainingSpace() < gpSize) {
err = _code->growBuffer(&_section->_buffer, gpSize);
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
}
#if !defined(ASMJIT_DISABLE_LOGGING)
if (_globalOptions & kOptionLoggingEnabled)
_code->_logger->logf(gpSize == 4 ? ".dd L%u\n" : ".dq L%u\n", Operand::unpackId(label.getId()));
#endif // !ASMJIT_DISABLE_LOGGING
err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, gpSize);
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
re->_sourceSectionId = _section->getId();
re->_sourceOffset = static_cast<uint64_t>(getOffset());
if (le->isBound()) {
re->_targetSectionId = le->getSectionId();
re->_data = static_cast<uint64_t>(static_cast<int64_t>(le->getOffset()));
}
else {
LabelLink* link = _code->newLabelLink(le, _section->getId(), getOffset(), 0);
if (ASMJIT_UNLIKELY(!link))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
link->relocId = re->getId();
}
// Emit dummy DWORD/QWORD depending on the address size.
::memset(_bufferPtr, 0, gpSize);
_bufferPtr += gpSize;
return kErrorOk;
}
Error Assembler::embedConstPool(const Label& label, const ConstPool& pool) {
if (_lastError) return _lastError;
if (!isLabelValid(label))
return DebugUtils::errored(kErrorInvalidLabel);
ASMJIT_PROPAGATE(align(kAlignData, static_cast<uint32_t>(pool.getAlignment())));
ASMJIT_PROPAGATE(bind(label));
size_t size = pool.getSize();
if (getRemainingSpace() < size) {
Error err = _code->growBuffer(&_section->_buffer, size);
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
}
uint8_t* p = _bufferPtr;
pool.fill(p);
#if !defined(ASMJIT_DISABLE_LOGGING)
if (_globalOptions & kOptionLoggingEnabled)
_code->_logger->logBinary(p, size);
#endif // !ASMJIT_DISABLE_LOGGING
_bufferPtr += size;
return kErrorOk;
}
// ============================================================================
// [asmjit::Assembler - Emit-Helpers]
// ============================================================================
#if !defined(ASMJIT_DISABLE_LOGGING)
void Assembler::_emitLog(
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3,
uint32_t relSize, uint32_t imLen, uint8_t* afterCursor) {
Logger* logger = _code->getLogger();
ASMJIT_ASSERT(logger != nullptr);
ASMJIT_ASSERT(options & CodeEmitter::kOptionLoggingEnabled);
StringBuilderTmp<256> sb;
uint32_t logOptions = logger->getOptions();
uint8_t* beforeCursor = _bufferPtr;
intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor);
sb.appendString(logger->getIndentation());
Operand_ opArray[6];
opArray[0].copyFrom(o0);
opArray[1].copyFrom(o1);
opArray[2].copyFrom(o2);
opArray[3].copyFrom(o3);
if (options & kOptionOp4Op5Used) {
opArray[4].copyFrom(_op4);
opArray[5].copyFrom(_op5);
}
else {
opArray[4].reset();
opArray[5].reset();
}
Logging::formatInstruction(
sb, logOptions,
this, getArchType(),
Inst::Detail(instId, options, _extraReg), opArray, 6);
if ((logOptions & Logger::kOptionBinaryForm) != 0)
Logging::formatLine(sb, _bufferPtr, emittedSize, relSize, imLen, getInlineComment());
else
Logging::formatLine(sb, nullptr, Globals::kInvalidIndex, 0, 0, getInlineComment());
logger->log(sb.getData(), sb.getLength());
}
Error Assembler::_emitFailed(
Error err,
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
StringBuilderTmp<256> sb;
sb.appendString(DebugUtils::errorAsString(err));
sb.appendString(": ");
Operand_ opArray[6];
opArray[0].copyFrom(o0);
opArray[1].copyFrom(o1);
opArray[2].copyFrom(o2);
opArray[3].copyFrom(o3);
if (options & kOptionOp4Op5Used) {
opArray[4].copyFrom(_op4);
opArray[5].copyFrom(_op5);
}
else {
opArray[4].reset();
opArray[5].reset();
}
Logging::formatInstruction(
sb, 0,
this, getArchType(),
Inst::Detail(instId, options, _extraReg), opArray, 6);
resetOptions();
resetExtraReg();
resetInlineComment();
return setLastError(err, sb.getData());
}
#endif
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"

View File

@ -1,154 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_ASSEMBLER_H
#define _ASMJIT_BASE_ASSEMBLER_H
// [Dependencies]
#include "../base/codeemitter.h"
#include "../base/codeholder.h"
#include "../base/operand.h"
#include "../base/simdtypes.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [asmjit::Assembler]
// ============================================================================
//! Base assembler.
//!
//! This class implements a base interface that is used by architecture
//! specific assemblers.
//!
//! \sa CodeCompiler.
class ASMJIT_VIRTAPI Assembler : public CodeEmitter {
public:
ASMJIT_NONCOPYABLE(Assembler)
typedef CodeEmitter Base;
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `Assembler` instance.
ASMJIT_API Assembler() noexcept;
//! Destroy the `Assembler` instance.
ASMJIT_API virtual ~Assembler() noexcept;
// --------------------------------------------------------------------------
// [Events]
// --------------------------------------------------------------------------
ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
// --------------------------------------------------------------------------
// [Code-Generation]
// --------------------------------------------------------------------------
using CodeEmitter::_emit;
ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) override;
ASMJIT_API Error _emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) override;
// --------------------------------------------------------------------------
// [Code-Buffer]
// --------------------------------------------------------------------------
//! Called by \ref CodeHolder::sync().
ASMJIT_API virtual void sync() noexcept;
//! Get the capacity of the current CodeBuffer.
ASMJIT_INLINE size_t getBufferCapacity() const noexcept { return (size_t)(_bufferEnd - _bufferData); }
//! Get the number of remaining bytes in the current CodeBuffer.
ASMJIT_INLINE size_t getRemainingSpace() const noexcept { return (size_t)(_bufferEnd - _bufferPtr); }
//! Get the current position in the CodeBuffer.
ASMJIT_INLINE size_t getOffset() const noexcept { return (size_t)(_bufferPtr - _bufferData); }
//! Set the current position in the CodeBuffer to `offset`.
//!
//! NOTE: The `offset` cannot be outside of the buffer length (even if it's
//! within buffer's capacity).
ASMJIT_API Error setOffset(size_t offset);
//! Get start of the CodeBuffer of the current section.
ASMJIT_INLINE uint8_t* getBufferData() const noexcept { return _bufferData; }
//! Get end (first invalid byte) of the current section.
ASMJIT_INLINE uint8_t* getBufferEnd() const noexcept { return _bufferEnd; }
//! Get pointer in the CodeBuffer of the current section.
ASMJIT_INLINE uint8_t* getBufferPtr() const noexcept { return _bufferPtr; }
// --------------------------------------------------------------------------
// [Code-Generation]
// --------------------------------------------------------------------------
ASMJIT_API Label newLabel() override;
ASMJIT_API Label newNamedLabel(
const char* name,
size_t nameLength = Globals::kInvalidIndex,
uint32_t type = Label::kTypeGlobal,
uint32_t parentId = 0) override;
ASMJIT_API Error bind(const Label& label) override;
ASMJIT_API Error embed(const void* data, uint32_t size) override;
ASMJIT_API Error embedLabel(const Label& label) override;
ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override;
ASMJIT_API Error comment(const char* s, size_t len = Globals::kInvalidIndex) override;
// --------------------------------------------------------------------------
// [Emit-Helpers]
// --------------------------------------------------------------------------
protected:
#if !defined(ASMJIT_DISABLE_LOGGING)
void _emitLog(
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3,
uint32_t relSize, uint32_t imLen, uint8_t* afterCursor);
Error _emitFailed(
Error err,
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3);
#else
ASMJIT_INLINE Error _emitFailed(
uint32_t err,
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
resetOptions();
resetInlineComment();
return setLastError(err);
}
#endif
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
public:
SectionEntry* _section; //!< Current section where the assembling happens.
uint8_t* _bufferData; //!< Start of the CodeBuffer of the current section.
uint8_t* _bufferEnd; //!< End (first invalid byte) of the current section.
uint8_t* _bufferPtr; //!< Pointer in the CodeBuffer of the current section.
Operand_ _op4; //!< 5th operand data, used only temporarily.
Operand_ _op5; //!< 6th operand data, used only temporarily.
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_ASSEMBLER_H

View File

@ -1,584 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Guard]
#include "../asmjit_build.h"
#if !defined(ASMJIT_DISABLE_BUILDER)
// [Dependencies]
#include "../base/codebuilder.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::CodeBuilder - Construction / Destruction]
// ============================================================================
CodeBuilder::CodeBuilder() noexcept
: CodeEmitter(kTypeBuilder),
_cbBaseZone(32768 - Zone::kZoneOverhead),
_cbDataZone(16384 - Zone::kZoneOverhead),
_cbPassZone(32768 - Zone::kZoneOverhead),
_cbHeap(&_cbBaseZone),
_cbPasses(),
_cbLabels(),
_firstNode(nullptr),
_lastNode(nullptr),
_cursor(nullptr),
_position(0),
_nodeFlags(0) {}
CodeBuilder::~CodeBuilder() noexcept {}
// ============================================================================
// [asmjit::CodeBuilder - Events]
// ============================================================================
Error CodeBuilder::onAttach(CodeHolder* code) noexcept {
return Base::onAttach(code);
}
Error CodeBuilder::onDetach(CodeHolder* code) noexcept {
_cbPasses.reset();
_cbLabels.reset();
_cbHeap.reset(&_cbBaseZone);
_cbBaseZone.reset(false);
_cbDataZone.reset(false);
_cbPassZone.reset(false);
_position = 0;
_nodeFlags = 0;
_firstNode = nullptr;
_lastNode = nullptr;
_cursor = nullptr;
return Base::onDetach(code);
}
// ============================================================================
// [asmjit::CodeBuilder - Node-Factory]
// ============================================================================
Error CodeBuilder::getCBLabel(CBLabel** pOut, uint32_t id) noexcept {
if (_lastError) return _lastError;
ASMJIT_ASSERT(_code != nullptr);
size_t index = Operand::unpackId(id);
if (ASMJIT_UNLIKELY(index >= _code->getLabelsCount()))
return DebugUtils::errored(kErrorInvalidLabel);
if (index >= _cbLabels.getLength())
ASMJIT_PROPAGATE(_cbLabels.resize(&_cbHeap, index + 1));
CBLabel* node = _cbLabels[index];
if (!node) {
node = newNodeT<CBLabel>(id);
if (ASMJIT_UNLIKELY(!node))
return DebugUtils::errored(kErrorNoHeapMemory);
_cbLabels[index] = node;
}
*pOut = node;
return kErrorOk;
}
Error CodeBuilder::registerLabelNode(CBLabel* node) noexcept {
if (_lastError) return _lastError;
ASMJIT_ASSERT(_code != nullptr);
// Don't call setLastError() from here, we are noexcept and we are called
// by `newLabelNode()` and `newFuncNode()`, which are noexcept as well.
uint32_t id;
ASMJIT_PROPAGATE(_code->newLabelId(id));
size_t index = Operand::unpackId(id);
// We just added one label so it must be true.
ASMJIT_ASSERT(_cbLabels.getLength() < index + 1);
ASMJIT_PROPAGATE(_cbLabels.resize(&_cbHeap, index + 1));
_cbLabels[index] = node;
node->_id = id;
return kErrorOk;
}
CBLabel* CodeBuilder::newLabelNode() noexcept {
CBLabel* node = newNodeT<CBLabel>();
if (!node || registerLabelNode(node) != kErrorOk)
return nullptr;
return node;
}
CBAlign* CodeBuilder::newAlignNode(uint32_t mode, uint32_t alignment) noexcept {
return newNodeT<CBAlign>(mode, alignment);
}
CBData* CodeBuilder::newDataNode(const void* data, uint32_t size) noexcept {
if (size > CBData::kInlineBufferSize) {
void* cloned = _cbDataZone.alloc(size);
if (!cloned) return nullptr;
if (data) ::memcpy(cloned, data, size);
data = cloned;
}
return newNodeT<CBData>(const_cast<void*>(data), size);
}
CBConstPool* CodeBuilder::newConstPool() noexcept {
CBConstPool* node = newNodeT<CBConstPool>();
if (!node || registerLabelNode(node) != kErrorOk)
return nullptr;
return node;
}
CBComment* CodeBuilder::newCommentNode(const char* s, size_t len) noexcept {
if (s) {
if (len == Globals::kInvalidIndex) len = ::strlen(s);
if (len > 0) {
s = static_cast<char*>(_cbDataZone.dup(s, len, true));
if (!s) return nullptr;
}
}
return newNodeT<CBComment>(s);
}
// ============================================================================
// [asmjit::CodeBuilder - Code-Emitter]
// ============================================================================
Label CodeBuilder::newLabel() {
uint32_t id = kInvalidValue;
if (!_lastError) {
CBLabel* node = newNodeT<CBLabel>(id);
if (ASMJIT_UNLIKELY(!node)) {
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
}
else {
Error err = registerLabelNode(node);
if (ASMJIT_UNLIKELY(err))
setLastError(err);
else
id = node->getId();
}
}
return Label(id);
}
Label CodeBuilder::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) {
uint32_t id = kInvalidValue;
if (!_lastError) {
CBLabel* node = newNodeT<CBLabel>(id);
if (ASMJIT_UNLIKELY(!node)) {
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
}
else {
Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId);
if (ASMJIT_UNLIKELY(err))
setLastError(err);
else
id = node->getId();
}
}
return Label(id);
}
Error CodeBuilder::bind(const Label& label) {
if (_lastError) return _lastError;
CBLabel* node;
Error err = getCBLabel(&node, label);
if (ASMJIT_UNLIKELY(err))
return setLastError(err);
addNode(node);
return kErrorOk;
}
Error CodeBuilder::align(uint32_t mode, uint32_t alignment) {
if (_lastError) return _lastError;
CBAlign* node = newAlignNode(mode, alignment);
if (ASMJIT_UNLIKELY(!node))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
addNode(node);
return kErrorOk;
}
Error CodeBuilder::embed(const void* data, uint32_t size) {
if (_lastError) return _lastError;
CBData* node = newDataNode(data, size);
if (ASMJIT_UNLIKELY(!node))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
addNode(node);
return kErrorOk;
}
Error CodeBuilder::embedLabel(const Label& label) {
if (_lastError) return _lastError;
CBLabelData* node = newNodeT<CBLabelData>(label.getId());
if (ASMJIT_UNLIKELY(!node))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
addNode(node);
return kErrorOk;
}
Error CodeBuilder::embedConstPool(const Label& label, const ConstPool& pool) {
if (_lastError) return _lastError;
if (!isLabelValid(label))
return setLastError(DebugUtils::errored(kErrorInvalidLabel));
ASMJIT_PROPAGATE(align(kAlignData, static_cast<uint32_t>(pool.getAlignment())));
ASMJIT_PROPAGATE(bind(label));
CBData* node = newDataNode(nullptr, static_cast<uint32_t>(pool.getSize()));
if (ASMJIT_UNLIKELY(!node))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
pool.fill(node->getData());
addNode(node);
return kErrorOk;
}
Error CodeBuilder::comment(const char* s, size_t len) {
if (_lastError) return _lastError;
CBComment* node = newCommentNode(s, len);
if (ASMJIT_UNLIKELY(!node))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
addNode(node);
return kErrorOk;
}
// ============================================================================
// [asmjit::CodeBuilder - Node-Management]
// ============================================================================
CBNode* CodeBuilder::addNode(CBNode* node) noexcept {
ASMJIT_ASSERT(node);
ASMJIT_ASSERT(node->_prev == nullptr);
ASMJIT_ASSERT(node->_next == nullptr);
if (!_cursor) {
if (!_firstNode) {
_firstNode = node;
_lastNode = node;
}
else {
node->_next = _firstNode;
_firstNode->_prev = node;
_firstNode = node;
}
}
else {
CBNode* prev = _cursor;
CBNode* next = _cursor->_next;
node->_prev = prev;
node->_next = next;
prev->_next = node;
if (next)
next->_prev = node;
else
_lastNode = node;
}
_cursor = node;
return node;
}
CBNode* CodeBuilder::addAfter(CBNode* node, CBNode* ref) noexcept {
ASMJIT_ASSERT(node);
ASMJIT_ASSERT(ref);
ASMJIT_ASSERT(node->_prev == nullptr);
ASMJIT_ASSERT(node->_next == nullptr);
CBNode* prev = ref;
CBNode* next = ref->_next;
node->_prev = prev;
node->_next = next;
prev->_next = node;
if (next)
next->_prev = node;
else
_lastNode = node;
return node;
}
CBNode* CodeBuilder::addBefore(CBNode* node, CBNode* ref) noexcept {
ASMJIT_ASSERT(node != nullptr);
ASMJIT_ASSERT(node->_prev == nullptr);
ASMJIT_ASSERT(node->_next == nullptr);
ASMJIT_ASSERT(ref != nullptr);
CBNode* prev = ref->_prev;
CBNode* next = ref;
node->_prev = prev;
node->_next = next;
next->_prev = node;
if (prev)
prev->_next = node;
else
_firstNode = node;
return node;
}
static ASMJIT_INLINE void CodeBuilder_nodeRemoved(CodeBuilder* self, CBNode* node_) noexcept {
if (node_->isJmpOrJcc()) {
CBJump* node = static_cast<CBJump*>(node_);
CBLabel* label = node->getTarget();
if (label) {
// Disconnect.
CBJump** pPrev = &label->_from;
for (;;) {
ASMJIT_ASSERT(*pPrev != nullptr);
CBJump* current = *pPrev;
if (!current) break;
if (current == node) {
*pPrev = node->_jumpNext;
break;
}
pPrev = &current->_jumpNext;
}
label->subNumRefs();
}
}
}
CBNode* CodeBuilder::removeNode(CBNode* node) noexcept {
CBNode* prev = node->_prev;
CBNode* next = node->_next;
if (_firstNode == node)
_firstNode = next;
else
prev->_next = next;
if (_lastNode == node)
_lastNode = prev;
else
next->_prev = prev;
node->_prev = nullptr;
node->_next = nullptr;
if (_cursor == node)
_cursor = prev;
CodeBuilder_nodeRemoved(this, node);
return node;
}
void CodeBuilder::removeNodes(CBNode* first, CBNode* last) noexcept {
if (first == last) {
removeNode(first);
return;
}
CBNode* prev = first->_prev;
CBNode* next = last->_next;
if (_firstNode == first)
_firstNode = next;
else
prev->_next = next;
if (_lastNode == last)
_lastNode = prev;
else
next->_prev = prev;
CBNode* node = first;
for (;;) {
CBNode* next = node->getNext();
ASMJIT_ASSERT(next != nullptr);
node->_prev = nullptr;
node->_next = nullptr;
if (_cursor == node)
_cursor = prev;
CodeBuilder_nodeRemoved(this, node);
if (node == last)
break;
node = next;
}
}
CBNode* CodeBuilder::setCursor(CBNode* node) noexcept {
CBNode* old = _cursor;
_cursor = node;
return old;
}
// ============================================================================
// [asmjit::CodeBuilder - Passes]
// ============================================================================
ASMJIT_FAVOR_SIZE CBPass* CodeBuilder::getPassByName(const char* name) const noexcept {
for (size_t i = 0, len = _cbPasses.getLength(); i < len; i++) {
CBPass* pass = _cbPasses[i];
if (::strcmp(pass->getName(), name) == 0)
return pass;
}
return nullptr;
}
ASMJIT_FAVOR_SIZE Error CodeBuilder::addPass(CBPass* pass) noexcept {
if (ASMJIT_UNLIKELY(pass == nullptr)) {
// Since this is directly called by `addPassT()` we treat `null` argument
// as out-of-memory condition. Otherwise it would be API misuse.
return DebugUtils::errored(kErrorNoHeapMemory);
}
else if (ASMJIT_UNLIKELY(pass->_cb)) {
// Kind of weird, but okay...
if (pass->_cb == this)
return kErrorOk;
return DebugUtils::errored(kErrorInvalidState);
}
ASMJIT_PROPAGATE(_cbPasses.append(&_cbHeap, pass));
pass->_cb = this;
return kErrorOk;
}
ASMJIT_FAVOR_SIZE Error CodeBuilder::deletePass(CBPass* pass) noexcept {
if (ASMJIT_UNLIKELY(pass == nullptr))
return DebugUtils::errored(kErrorInvalidArgument);
if (pass->_cb != nullptr) {
if (pass->_cb != this)
return DebugUtils::errored(kErrorInvalidState);
size_t index = _cbPasses.indexOf(pass);
ASMJIT_ASSERT(index != Globals::kInvalidIndex);
pass->_cb = nullptr;
_cbPasses.removeAt(index);
}
pass->~CBPass();
return kErrorOk;
}
// ============================================================================
// [asmjit::CodeBuilder - Serialization]
// ============================================================================
Error CodeBuilder::serialize(CodeEmitter* dst) {
Error err = kErrorOk;
CBNode* node_ = getFirstNode();
do {
dst->setInlineComment(node_->getInlineComment());
switch (node_->getType()) {
case CBNode::kNodeAlign: {
CBAlign* node = static_cast<CBAlign*>(node_);
err = dst->align(node->getMode(), node->getAlignment());
break;
}
case CBNode::kNodeData: {
CBData* node = static_cast<CBData*>(node_);
err = dst->embed(node->getData(), node->getSize());
break;
}
case CBNode::kNodeFunc:
case CBNode::kNodeLabel: {
CBLabel* node = static_cast<CBLabel*>(node_);
err = dst->bind(node->getLabel());
break;
}
case CBNode::kNodeLabelData: {
CBLabelData* node = static_cast<CBLabelData*>(node_);
err = dst->embedLabel(node->getLabel());
break;
}
case CBNode::kNodeConstPool: {
CBConstPool* node = static_cast<CBConstPool*>(node_);
err = dst->embedConstPool(node->getLabel(), node->getConstPool());
break;
}
case CBNode::kNodeInst:
case CBNode::kNodeFuncCall: {
CBInst* node = node_->as<CBInst>();
dst->setOptions(node->getOptions());
dst->setExtraReg(node->getExtraReg());
err = dst->emitOpArray(node->getInstId(), node->getOpArray(), node->getOpCount());
break;
}
case CBNode::kNodeComment: {
CBComment* node = static_cast<CBComment*>(node_);
err = dst->comment(node->getInlineComment());
break;
}
default:
break;
}
if (err) break;
node_ = node_->getNext();
} while (node_);
return err;
}
// ============================================================================
// [asmjit::CBPass]
// ============================================================================
CBPass::CBPass(const char* name) noexcept
: _cb(nullptr),
_name(name) {}
CBPass::~CBPass() noexcept {}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_BUILDER

View File

@ -1,915 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CODEBUILDER_H
#define _ASMJIT_BASE_CODEBUILDER_H
#include "../asmjit_build.h"
#if !defined(ASMJIT_DISABLE_BUILDER)
// [Dependencies]
#include "../base/assembler.h"
#include "../base/codeholder.h"
#include "../base/constpool.h"
#include "../base/inst.h"
#include "../base/operand.h"
#include "../base/utils.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [Forward Declarations]
// ============================================================================
class CBNode;
class CBPass;
class CBAlign;
class CBComment;
class CBConstPool;
class CBData;
class CBInst;
class CBJump;
class CBLabel;
class CBLabelData;
class CBSentinel;
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [asmjit::CodeBuilder]
// ============================================================================
class ASMJIT_VIRTAPI CodeBuilder : public CodeEmitter {
public:
ASMJIT_NONCOPYABLE(CodeBuilder)
typedef CodeEmitter Base;
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CodeBuilder` instance.
ASMJIT_API CodeBuilder() noexcept;
//! Destroy the `CodeBuilder` instance.
ASMJIT_API virtual ~CodeBuilder() noexcept;
// --------------------------------------------------------------------------
// [Events]
// --------------------------------------------------------------------------
ASMJIT_API virtual Error onAttach(CodeHolder* code) noexcept override;
ASMJIT_API virtual Error onDetach(CodeHolder* code) noexcept override;
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get a vector of CBPass objects that will be executed by `process()`.
ASMJIT_INLINE const ZoneVector<CBPass*>& getPasses() const noexcept { return _cbPasses; }
//! Get a vector of CBLabel nodes.
//!
//! NOTE: If a label of some index is not associated with `CodeBuilder` it
//! would be null, so always check for nulls if you iterate over the vector.
ASMJIT_INLINE const ZoneVector<CBLabel*>& getLabels() const noexcept { return _cbLabels; }
//! Get the first node.
ASMJIT_INLINE CBNode* getFirstNode() const noexcept { return _firstNode; }
//! Get the last node.
ASMJIT_INLINE CBNode* getLastNode() const noexcept { return _lastNode; }
// --------------------------------------------------------------------------
// [Node-Management]
// --------------------------------------------------------------------------
//! \internal
template<typename T>
ASMJIT_INLINE T* newNodeT() noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this); }
//! \internal
template<typename T, typename P0>
ASMJIT_INLINE T* newNodeT(P0 p0) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0); }
//! \internal
template<typename T, typename P0, typename P1>
ASMJIT_INLINE T* newNodeT(P0 p0, P1 p1) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0, p1); }
//! \internal
template<typename T, typename P0, typename P1, typename P2>
ASMJIT_INLINE T* newNodeT(P0 p0, P1 p1, P2 p2) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0, p1, p2); }
ASMJIT_API Error registerLabelNode(CBLabel* node) noexcept;
//! Get `CBLabel` by `id`.
ASMJIT_API Error getCBLabel(CBLabel** pOut, uint32_t id) noexcept;
//! Get `CBLabel` by `label`.
ASMJIT_INLINE Error getCBLabel(CBLabel** pOut, const Label& label) noexcept { return getCBLabel(pOut, label.getId()); }
//! Create a new \ref CBLabel node.
ASMJIT_API CBLabel* newLabelNode() noexcept;
//! Create a new \ref CBAlign node.
ASMJIT_API CBAlign* newAlignNode(uint32_t mode, uint32_t alignment) noexcept;
//! Create a new \ref CBData node.
ASMJIT_API CBData* newDataNode(const void* data, uint32_t size) noexcept;
//! Create a new \ref CBConstPool node.
ASMJIT_API CBConstPool* newConstPool() noexcept;
//! Create a new \ref CBComment node.
ASMJIT_API CBComment* newCommentNode(const char* s, size_t len) noexcept;
// --------------------------------------------------------------------------
// [Code-Emitter]
// --------------------------------------------------------------------------
ASMJIT_API virtual Label newLabel() override;
ASMJIT_API virtual Label newNamedLabel(const char* name, size_t nameLength = Globals::kInvalidIndex, uint32_t type = Label::kTypeGlobal, uint32_t parentId = kInvalidValue) override;
ASMJIT_API virtual Error bind(const Label& label) override;
ASMJIT_API virtual Error align(uint32_t mode, uint32_t alignment) override;
ASMJIT_API virtual Error embed(const void* data, uint32_t size) override;
ASMJIT_API virtual Error embedLabel(const Label& label) override;
ASMJIT_API virtual Error embedConstPool(const Label& label, const ConstPool& pool) override;
ASMJIT_API virtual Error comment(const char* s, size_t len = Globals::kInvalidIndex) override;
// --------------------------------------------------------------------------
// [Node-Management]
// --------------------------------------------------------------------------
//! Add `node` after the current and set current to `node`.
ASMJIT_API CBNode* addNode(CBNode* node) noexcept;
//! Insert `node` after `ref`.
ASMJIT_API CBNode* addAfter(CBNode* node, CBNode* ref) noexcept;
//! Insert `node` before `ref`.
ASMJIT_API CBNode* addBefore(CBNode* node, CBNode* ref) noexcept;
//! Remove `node`.
ASMJIT_API CBNode* removeNode(CBNode* node) noexcept;
//! Remove multiple nodes.
ASMJIT_API void removeNodes(CBNode* first, CBNode* last) noexcept;
//! Get current node.
//!
//! \note If this method returns null it means that nothing has been
//! emitted yet.
ASMJIT_INLINE CBNode* getCursor() const noexcept { return _cursor; }
//! Set the current node without returning the previous node.
ASMJIT_INLINE void _setCursor(CBNode* node) noexcept { _cursor = node; }
//! Set the current node to `node` and return the previous one.
ASMJIT_API CBNode* setCursor(CBNode* node) noexcept;
// --------------------------------------------------------------------------
// [Passes]
// --------------------------------------------------------------------------
template<typename T>
ASMJIT_INLINE T* newPassT() noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(); }
template<typename T, typename P0>
ASMJIT_INLINE T* newPassT(P0 p0) noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(p0); }
template<typename T, typename P0, typename P1>
ASMJIT_INLINE T* newPassT(P0 p0, P1 p1) noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(p0, p1); }
template<typename T>
ASMJIT_INLINE Error addPassT() noexcept { return addPass(newPassT<T>()); }
template<typename T, typename P0>
ASMJIT_INLINE Error addPassT(P0 p0) noexcept { return addPass(newPassT<P0>(p0)); }
template<typename T, typename P0, typename P1>
ASMJIT_INLINE Error addPassT(P0 p0, P1 p1) noexcept { return addPass(newPassT<P0, P1>(p0, p1)); }
//! Get a `CBPass` by name.
ASMJIT_API CBPass* getPassByName(const char* name) const noexcept;
//! Add `pass` to the list of passes.
ASMJIT_API Error addPass(CBPass* pass) noexcept;
//! Remove `pass` from the list of passes and delete it.
ASMJIT_API Error deletePass(CBPass* pass) noexcept;
// --------------------------------------------------------------------------
// [Serialization]
// --------------------------------------------------------------------------
ASMJIT_API virtual Error serialize(CodeEmitter* dst);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
Zone _cbBaseZone; //!< Base zone used to allocate nodes and `CBPass`.
Zone _cbDataZone; //!< Data zone used to allocate data and names.
Zone _cbPassZone; //!< Zone passed to `CBPass::process()`.
ZoneHeap _cbHeap; //!< ZoneHeap that uses `_cbBaseZone`.
ZoneVector<CBPass*> _cbPasses; //!< Array of `CBPass` objects.
ZoneVector<CBLabel*> _cbLabels; //!< Maps label indexes to `CBLabel` nodes.
CBNode* _firstNode; //!< First node of the current section.
CBNode* _lastNode; //!< Last node of the current section.
CBNode* _cursor; //!< Current node (cursor).
uint32_t _position; //!< Flow-id assigned to each new node.
uint32_t _nodeFlags; //!< Flags assigned to each new node.
};
// ============================================================================
// [asmjit::CBPass]
// ============================================================================
//! `CodeBuilder` pass used to code transformations, analysis, and lowering.
class ASMJIT_VIRTAPI CBPass {
public:
ASMJIT_NONCOPYABLE(CBPass);
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_API CBPass(const char* name) noexcept;
ASMJIT_API virtual ~CBPass() noexcept;
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
//! Process the code stored in CodeBuffer `cb`.
//!
//! This is the only function that is called by the `CodeBuilder` to process
//! the code. It passes the CodeBuilder itself (`cb`) and also a zone memory
//! allocator `zone`, which will be reset after the `process()` returns. The
//! allocator should be used for all allocations as it's fast and everything
//! it allocates will be released at once when `process()` returns.
virtual Error process(Zone* zone) noexcept = 0;
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE const CodeBuilder* cb() const noexcept { return _cb; }
ASMJIT_INLINE const char* getName() const noexcept { return _name; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
CodeBuilder* _cb; //!< CodeBuilder this pass is assigned to.
const char* _name; //!< Name of the pass.
};
// ============================================================================
// [asmjit::CBNode]
// ============================================================================
//! Node (CodeBuilder).
//!
//! Every node represents a building-block used by \ref CodeBuilder. It can be
//! instruction, data, label, comment, directive, or any other high-level
//! representation that can be transformed to the building blocks mentioned.
//! Every class that inherits \ref CodeBuilder can define its own nodes that it
//! can lower to basic nodes.
class CBNode {
public:
ASMJIT_NONCOPYABLE(CBNode)
// --------------------------------------------------------------------------
// [Type]
// --------------------------------------------------------------------------
//! Type of \ref CBNode.
ASMJIT_ENUM(NodeType) {
kNodeNone = 0, //!< Invalid node (internal, don't use).
// [CodeBuilder]
kNodeInst = 1, //!< Node is \ref CBInst or \ref CBJump.
kNodeData = 2, //!< Node is \ref CBData.
kNodeAlign = 3, //!< Node is \ref CBAlign.
kNodeLabel = 4, //!< Node is \ref CBLabel.
kNodeLabelData = 5, //!< Node is \ref CBLabelData.
kNodeConstPool = 6, //!< Node is \ref CBConstPool.
kNodeComment = 7, //!< Node is \ref CBComment.
kNodeSentinel = 8, //!< Node is \ref CBSentinel.
// [CodeCompiler]
kNodeFunc = 16, //!< Node is \ref CCFunc (considered as \ref CBLabel by \ref CodeBuilder).
kNodeFuncExit = 17, //!< Node is \ref CCFuncRet.
kNodeFuncCall = 18, //!< Node is \ref CCFuncCall.
kNodePushArg = 19, //!< Node is \ref CCPushArg.
kNodeHint = 20, //!< Node is \ref CCHint.
// [UserDefined]
kNodeUser = 32 //!< First id of a user-defined node.
};
// --------------------------------------------------------------------------
// [Flags]
// --------------------------------------------------------------------------
ASMJIT_ENUM(Flags) {
//! The node has been translated by the CodeCompiler.
kFlagIsTranslated = 0x0001,
//! If the node can be safely removed (has no effect).
kFlagIsRemovable = 0x0004,
//! If the node is informative only and can be safely removed.
kFlagIsInformative = 0x0008,
//! If the `CBInst` is a jump.
kFlagIsJmp = 0x0010,
//! If the `CBInst` is a conditional jump.
kFlagIsJcc = 0x0020,
//! If the `CBInst` is an unconditional jump or conditional jump that is
//! likely to be taken.
kFlagIsTaken = 0x0040,
//! If the `CBNode` will return from a function.
//!
//! This flag is used by both `CBSentinel` and `CCFuncRet`.
kFlagIsRet = 0x0080,
//! Whether the instruction is special.
kFlagIsSpecial = 0x0100,
//! Whether the instruction is an FPU instruction.
kFlagIsFp = 0x0200
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new \ref CBNode - always use \ref CodeBuilder to allocate nodes.
ASMJIT_INLINE CBNode(CodeBuilder* cb, uint32_t type) noexcept {
_prev = nullptr;
_next = nullptr;
_type = static_cast<uint8_t>(type);
_opCount = 0;
_flags = static_cast<uint16_t>(cb->_nodeFlags);
_position = cb->_position;
_inlineComment = nullptr;
_passData = nullptr;
}
//! Destroy the `CBNode` instance (NEVER CALLED).
ASMJIT_INLINE ~CBNode() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
template<typename T>
ASMJIT_INLINE T* as() noexcept { return static_cast<T*>(this); }
template<typename T>
ASMJIT_INLINE const T* as() const noexcept { return static_cast<const T*>(this); }
//! Get previous node in the compiler stream.
ASMJIT_INLINE CBNode* getPrev() const noexcept { return _prev; }
//! Get next node in the compiler stream.
ASMJIT_INLINE CBNode* getNext() const noexcept { return _next; }
//! Get the node type, see \ref Type.
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
//! Get the node flags.
ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; }
//! Get whether the instruction has flag `flag`.
ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (static_cast<uint32_t>(_flags) & flag) != 0; }
//! Set node flags to `flags`.
ASMJIT_INLINE void setFlags(uint32_t flags) noexcept { _flags = static_cast<uint16_t>(flags); }
//! Add instruction `flags`.
ASMJIT_INLINE void orFlags(uint32_t flags) noexcept { _flags |= static_cast<uint16_t>(flags); }
//! And instruction `flags`.
ASMJIT_INLINE void andFlags(uint32_t flags) noexcept { _flags &= static_cast<uint16_t>(flags); }
//! Clear instruction `flags`.
ASMJIT_INLINE void andNotFlags(uint32_t flags) noexcept { _flags &= ~static_cast<uint16_t>(flags); }
//! Get whether the node has been translated.
ASMJIT_INLINE bool isTranslated() const noexcept { return hasFlag(kFlagIsTranslated); }
//! Get whether the node is removable if it's in unreachable code block.
ASMJIT_INLINE bool isRemovable() const noexcept { return hasFlag(kFlagIsRemovable); }
//! Get whether the node is informative only (comment, hint).
ASMJIT_INLINE bool isInformative() const noexcept { return hasFlag(kFlagIsInformative); }
//! Whether the node is `CBLabel`.
ASMJIT_INLINE bool isLabel() const noexcept { return _type == kNodeLabel; }
//! Whether the `CBInst` node is an unconditional jump.
ASMJIT_INLINE bool isJmp() const noexcept { return hasFlag(kFlagIsJmp); }
//! Whether the `CBInst` node is a conditional jump.
ASMJIT_INLINE bool isJcc() const noexcept { return hasFlag(kFlagIsJcc); }
//! Whether the `CBInst` node is a conditional/unconditional jump.
ASMJIT_INLINE bool isJmpOrJcc() const noexcept { return hasFlag(kFlagIsJmp | kFlagIsJcc); }
//! Whether the `CBInst` node is a return.
ASMJIT_INLINE bool isRet() const noexcept { return hasFlag(kFlagIsRet); }
//! Get whether the node is `CBInst` and the instruction is special.
ASMJIT_INLINE bool isSpecial() const noexcept { return hasFlag(kFlagIsSpecial); }
//! Get whether the node is `CBInst` and the instruction uses x87-FPU.
ASMJIT_INLINE bool isFp() const noexcept { return hasFlag(kFlagIsFp); }
ASMJIT_INLINE bool hasPosition() const noexcept { return _position != 0; }
//! Get flow index.
ASMJIT_INLINE uint32_t getPosition() const noexcept { return _position; }
//! Set flow index.
ASMJIT_INLINE void setPosition(uint32_t position) noexcept { _position = position; }
//! Get if the node has an inline comment.
ASMJIT_INLINE bool hasInlineComment() const noexcept { return _inlineComment != nullptr; }
//! Get an inline comment string.
ASMJIT_INLINE const char* getInlineComment() const noexcept { return _inlineComment; }
//! Set an inline comment string to `s`.
ASMJIT_INLINE void setInlineComment(const char* s) noexcept { _inlineComment = s; }
//! Set an inline comment string to null.
ASMJIT_INLINE void resetInlineComment() noexcept { _inlineComment = nullptr; }
//! Get if the node has associated work-data.
ASMJIT_INLINE bool hasPassData() const noexcept { return _passData != nullptr; }
//! Get work-data - data used during processing & transformations.
template<typename T>
ASMJIT_INLINE T* getPassData() const noexcept { return (T*)_passData; }
//! Set work-data to `data`.
template<typename T>
ASMJIT_INLINE void setPassData(T* data) noexcept { _passData = (void*)data; }
//! Reset work-data to null.
ASMJIT_INLINE void resetPassData() noexcept { _passData = nullptr; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
CBNode* _prev; //!< Previous node.
CBNode* _next; //!< Next node.
uint8_t _type; //!< Node type, see \ref NodeType.
uint8_t _opCount; //!< Count of operands or zero.
uint16_t _flags; //!< Flags, different meaning for every type of the node.
uint32_t _position; //!< Flow index.
const char* _inlineComment; //!< Inline comment or null if not used.
void* _passData; //!< Data used exclusively by the current `CBPass`.
};
// ============================================================================
// [asmjit::CBInst]
// ============================================================================
//! Instruction (CodeBuilder).
//!
//! Wraps an instruction with its options and operands.
class CBInst : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBInst)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBInst` instance.
ASMJIT_INLINE CBInst(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept
: CBNode(cb, kNodeInst) {
orFlags(kFlagIsRemovable);
_instDetail.instId = static_cast<uint16_t>(instId);
_instDetail.options = options;
_opCount = static_cast<uint8_t>(opCount);
_opArray = opArray;
_updateMemOp();
}
//! Destroy the `CBInst` instance (NEVER CALLED).
ASMJIT_INLINE ~CBInst() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE Inst::Detail& getInstDetail() noexcept { return _instDetail; }
ASMJIT_INLINE const Inst::Detail& getInstDetail() const noexcept { return _instDetail; }
//! Get the instruction id, see \ref Inst::Id.
ASMJIT_INLINE uint32_t getInstId() const noexcept { return _instDetail.instId; }
//! Set the instruction id to `instId`, see \ref Inst::Id.
ASMJIT_INLINE void setInstId(uint32_t instId) noexcept { _instDetail.instId = instId; }
//! Whether the instruction is either a jump or a conditional jump likely to be taken.
ASMJIT_INLINE bool isTaken() const noexcept { return hasFlag(kFlagIsTaken); }
//! Get emit options.
ASMJIT_INLINE uint32_t getOptions() const noexcept { return _instDetail.options; }
//! Set emit options.
ASMJIT_INLINE void setOptions(uint32_t options) noexcept { _instDetail.options = options; }
//! Add emit options.
ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _instDetail.options |= options; }
//! Mask emit options.
ASMJIT_INLINE void andOptions(uint32_t options) noexcept { _instDetail.options &= options; }
//! Clear emit options.
ASMJIT_INLINE void delOptions(uint32_t options) noexcept { _instDetail.options &= ~options; }
//! Get if the node has an extra register operand.
ASMJIT_INLINE bool hasExtraReg() const noexcept { return _instDetail.hasExtraReg(); }
//! Get extra register operand.
ASMJIT_INLINE RegOnly& getExtraReg() noexcept { return _instDetail.extraReg; }
//! \overload
ASMJIT_INLINE const RegOnly& getExtraReg() const noexcept { return _instDetail.extraReg; }
//! Set extra register operand to `reg`.
ASMJIT_INLINE void setExtraReg(const Reg& reg) noexcept { _instDetail.extraReg.init(reg); }
//! Set extra register operand to `reg`.
ASMJIT_INLINE void setExtraReg(const RegOnly& reg) noexcept { _instDetail.extraReg.init(reg); }
//! Reset extra register operand.
ASMJIT_INLINE void resetExtraReg() noexcept { _instDetail.extraReg.reset(); }
//! Get operands count.
ASMJIT_INLINE uint32_t getOpCount() const noexcept { return _opCount; }
//! Get operands list.
ASMJIT_INLINE Operand* getOpArray() noexcept { return _opArray; }
//! \overload
ASMJIT_INLINE const Operand* getOpArray() const noexcept { return _opArray; }
//! Get whether the instruction contains a memory operand.
ASMJIT_INLINE bool hasMemOp() const noexcept { return _memOpIndex != 0xFF; }
//! Get memory operand.
//!
//! NOTE: Can only be called if the instruction has such operand,
//! see `hasMemOp()`.
ASMJIT_INLINE Mem* getMemOp() const noexcept {
ASMJIT_ASSERT(hasMemOp());
return static_cast<Mem*>(&_opArray[_memOpIndex]);
}
//! \overload
template<typename T>
ASMJIT_INLINE T* getMemOp() const noexcept {
ASMJIT_ASSERT(hasMemOp());
return static_cast<T*>(&_opArray[_memOpIndex]);
}
//! Set memory operand index, `0xFF` means no memory operand.
ASMJIT_INLINE void setMemOpIndex(uint32_t index) noexcept { _memOpIndex = static_cast<uint8_t>(index); }
//! Reset memory operand index to `0xFF` (no operand).
ASMJIT_INLINE void resetMemOpIndex() noexcept { _memOpIndex = 0xFF; }
// --------------------------------------------------------------------------
// [Utils]
// --------------------------------------------------------------------------
ASMJIT_INLINE void _updateMemOp() noexcept {
Operand* opArray = getOpArray();
uint32_t opCount = getOpCount();
uint32_t i;
for (i = 0; i < opCount; i++)
if (opArray[i].isMem())
goto Update;
i = 0xFF;
Update:
setMemOpIndex(i);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
Inst::Detail _instDetail; //!< Instruction id, options, and extra register.
uint8_t _memOpIndex; //!< \internal
uint8_t _reserved[7]; //!< \internal
Operand* _opArray; //!< Instruction operands.
};
// ============================================================================
// [asmjit::CBInstEx]
// ============================================================================
struct CBInstEx : public CBInst {
Operand _op4;
Operand _op5;
};
// ============================================================================
// [asmjit::CBJump]
// ============================================================================
//! Asm jump (conditional or direct).
//!
//! Extension of `CBInst` node, which stores more information about the jump.
class CBJump : public CBInst {
public:
ASMJIT_NONCOPYABLE(CBJump)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE CBJump(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept
: CBInst(cb, instId, options, opArray, opCount),
_target(nullptr),
_jumpNext(nullptr) {}
ASMJIT_INLINE ~CBJump() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE CBLabel* getTarget() const noexcept { return _target; }
ASMJIT_INLINE CBJump* getJumpNext() const noexcept { return _jumpNext; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
CBLabel* _target; //!< Target node.
CBJump* _jumpNext; //!< Next jump to the same target in a single linked-list.
};
// ============================================================================
// [asmjit::CBData]
// ============================================================================
//! Asm data (CodeBuilder).
//!
//! Wraps `.data` directive. The node contains data that will be placed at the
//! node's position in the assembler stream. The data is considered to be RAW;
//! no analysis nor byte-order conversion is performed on RAW data.
class CBData : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBData)
enum { kInlineBufferSize = static_cast<int>(64 - sizeof(CBNode) - 4) };
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBData` instance.
ASMJIT_INLINE CBData(CodeBuilder* cb, void* data, uint32_t size) noexcept : CBNode(cb, kNodeData) {
if (size <= kInlineBufferSize) {
if (data) ::memcpy(_buf, data, size);
}
else {
_externalPtr = static_cast<uint8_t*>(data);
}
_size = size;
}
//! Destroy the `CBData` instance (NEVER CALLED).
ASMJIT_INLINE ~CBData() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get size of the data.
uint32_t getSize() const noexcept { return _size; }
//! Get pointer to the data.
uint8_t* getData() const noexcept { return _size <= kInlineBufferSize ? const_cast<uint8_t*>(_buf) : _externalPtr; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
union {
struct {
uint8_t _buf[kInlineBufferSize]; //!< Embedded data buffer.
uint32_t _size; //!< Size of the data.
};
struct {
uint8_t* _externalPtr; //!< Pointer to external data.
};
};
};
// ============================================================================
// [asmjit::CBAlign]
// ============================================================================
//! Align directive (CodeBuilder).
//!
//! Wraps `.align` directive.
class CBAlign : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBAlign)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBAlign` instance.
ASMJIT_INLINE CBAlign(CodeBuilder* cb, uint32_t mode, uint32_t alignment) noexcept
: CBNode(cb, kNodeAlign),
_mode(mode),
_alignment(alignment) {}
//! Destroy the `CBAlign` instance (NEVER CALLED).
ASMJIT_INLINE ~CBAlign() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get align mode.
ASMJIT_INLINE uint32_t getMode() const noexcept { return _mode; }
//! Set align mode.
ASMJIT_INLINE void setMode(uint32_t mode) noexcept { _mode = mode; }
//! Get align offset in bytes.
ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; }
//! Set align offset in bytes to `offset`.
ASMJIT_INLINE void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint32_t _mode; //!< Align mode, see \ref AlignMode.
uint32_t _alignment; //!< Alignment (in bytes).
};
// ============================================================================
// [asmjit::CBLabel]
// ============================================================================
//! Label (CodeBuilder).
class CBLabel : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBLabel)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBLabel` instance.
ASMJIT_INLINE CBLabel(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept
: CBNode(cb, kNodeLabel),
_id(id),
_numRefs(0),
_from(nullptr) {}
//! Destroy the `CBLabel` instance (NEVER CALLED).
ASMJIT_INLINE ~CBLabel() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the label id.
ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
//! Get the label as `Label` operand.
ASMJIT_INLINE Label getLabel() const noexcept { return Label(_id); }
//! Get first jmp instruction.
ASMJIT_INLINE CBJump* getFrom() const noexcept { return _from; }
//! Get number of jumps to this target.
ASMJIT_INLINE uint32_t getNumRefs() const noexcept { return _numRefs; }
//! Set number of jumps to this target.
ASMJIT_INLINE void setNumRefs(uint32_t i) noexcept { _numRefs = i; }
//! Add number of jumps to this target.
ASMJIT_INLINE void addNumRefs(uint32_t i = 1) noexcept { _numRefs += i; }
//! Subtract number of jumps to this target.
ASMJIT_INLINE void subNumRefs(uint32_t i = 1) noexcept { _numRefs -= i; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint32_t _id; //!< Label id.
uint32_t _numRefs; //!< Count of jumps here.
CBJump* _from; //!< Linked-list of nodes that can jump here.
};
// ============================================================================
// [asmjit::CBLabelData]
// ============================================================================
class CBLabelData : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBLabelData)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBLabelData` instance.
ASMJIT_INLINE CBLabelData(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept
: CBNode(cb, kNodeLabelData),
_id(id) {}
//! Destroy the `CBLabelData` instance (NEVER CALLED).
ASMJIT_INLINE ~CBLabelData() noexcept {}
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
//! Get the label id.
ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
//! Get the label as `Label` operand.
ASMJIT_INLINE Label getLabel() const noexcept { return Label(_id); }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint32_t _id;
};
// ============================================================================
// [asmjit::CBConstPool]
// ============================================================================
class CBConstPool : public CBLabel {
public:
ASMJIT_NONCOPYABLE(CBConstPool)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBConstPool` instance.
ASMJIT_INLINE CBConstPool(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept
: CBLabel(cb, id),
_constPool(&cb->_cbBaseZone) { _type = kNodeConstPool; }
//! Destroy the `CBConstPool` instance (NEVER CALLED).
ASMJIT_INLINE ~CBConstPool() noexcept {}
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
ASMJIT_INLINE ConstPool& getConstPool() noexcept { return _constPool; }
ASMJIT_INLINE const ConstPool& getConstPool() const noexcept { return _constPool; }
//! Get whether the constant-pool is empty.
ASMJIT_INLINE bool isEmpty() const noexcept { return _constPool.isEmpty(); }
//! Get the size of the constant-pool in bytes.
ASMJIT_INLINE size_t getSize() const noexcept { return _constPool.getSize(); }
//! Get minimum alignment.
ASMJIT_INLINE size_t getAlignment() const noexcept { return _constPool.getAlignment(); }
//! See \ref ConstPool::add().
ASMJIT_INLINE Error add(const void* data, size_t size, size_t& dstOffset) noexcept {
return _constPool.add(data, size, dstOffset);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
ConstPool _constPool;
};
// ============================================================================
// [asmjit::CBComment]
// ============================================================================
//! Comment (CodeBuilder).
class CBComment : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBComment)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBComment` instance.
ASMJIT_INLINE CBComment(CodeBuilder* cb, const char* comment) noexcept : CBNode(cb, kNodeComment) {
orFlags(kFlagIsRemovable | kFlagIsInformative);
_inlineComment = comment;
}
//! Destroy the `CBComment` instance (NEVER CALLED).
ASMJIT_INLINE ~CBComment() noexcept {}
};
// ============================================================================
// [asmjit::CBSentinel]
// ============================================================================
//! Sentinel (CodeBuilder).
//!
//! Sentinel is a marker that is completely ignored by the code builder. It's
//! used to remember a position in a code as it never gets removed by any pass.
class CBSentinel : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBSentinel)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBSentinel` instance.
ASMJIT_INLINE CBSentinel(CodeBuilder* cb) noexcept : CBNode(cb, kNodeSentinel) {}
//! Destroy the `CBSentinel` instance (NEVER CALLED).
ASMJIT_INLINE ~CBSentinel() noexcept {}
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_BUILDER
#endif // _ASMJIT_BASE_CODEBUILDER_H

View File

@ -1,573 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Guard]
#include "../asmjit_build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies]
#include "../base/assembler.h"
#include "../base/codecompiler.h"
#include "../base/cpuinfo.h"
#include "../base/logging.h"
#include "../base/regalloc_p.h"
#include "../base/utils.h"
#include <stdarg.h>
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [Constants]
// ============================================================================
static const char noName[1] = { '\0' };
// ============================================================================
// [asmjit::CCFuncCall - Arg / Ret]
// ============================================================================
bool CCFuncCall::_setArg(uint32_t i, const Operand_& op) noexcept {
if ((i & ~kFuncArgHi) >= _funcDetail.getArgCount())
return false;
_args[i] = op;
return true;
}
bool CCFuncCall::_setRet(uint32_t i, const Operand_& op) noexcept {
if (i >= 2)
return false;
_ret[i] = op;
return true;
}
// ============================================================================
// [asmjit::CodeCompiler - Construction / Destruction]
// ============================================================================
CodeCompiler::CodeCompiler() noexcept
: CodeBuilder(),
_func(nullptr),
_vRegZone(4096 - Zone::kZoneOverhead),
_vRegArray(),
_localConstPool(nullptr),
_globalConstPool(nullptr) {
_type = kTypeCompiler;
}
CodeCompiler::~CodeCompiler() noexcept {}
// ============================================================================
// [asmjit::CodeCompiler - Events]
// ============================================================================
Error CodeCompiler::onAttach(CodeHolder* code) noexcept {
return Base::onAttach(code);
}
Error CodeCompiler::onDetach(CodeHolder* code) noexcept {
_func = nullptr;
_localConstPool = nullptr;
_globalConstPool = nullptr;
_vRegArray.reset();
_vRegZone.reset(false);
return Base::onDetach(code);
}
// ============================================================================
// [asmjit::CodeCompiler - Node-Factory]
// ============================================================================
CCHint* CodeCompiler::newHintNode(Reg& r, uint32_t hint, uint32_t value) noexcept {
if (!r.isVirtReg()) return nullptr;
VirtReg* vr = getVirtReg(r);
return newNodeT<CCHint>(vr, hint, value);
}
// ============================================================================
// [asmjit::CodeCompiler - Func]
// ============================================================================
CCFunc* CodeCompiler::newFunc(const FuncSignature& sign) noexcept {
Error err;
CCFunc* func = newNodeT<CCFunc>();
if (!func) goto _NoMemory;
err = registerLabelNode(func);
if (ASMJIT_UNLIKELY(err)) {
// TODO: Calls setLastError, maybe rethink noexcept?
setLastError(err);
return nullptr;
}
// Create helper nodes.
func->_exitNode = newLabelNode();
func->_end = newNodeT<CBSentinel>();
if (!func->_exitNode || !func->_end)
goto _NoMemory;
// Function prototype.
err = func->getDetail().init(sign);
if (err != kErrorOk) {
setLastError(err);
return nullptr;
}
// If the CodeInfo guarantees higher alignment honor it.
if (_codeInfo.getStackAlignment() > func->_funcDetail._callConv.getNaturalStackAlignment())
func->_funcDetail._callConv.setNaturalStackAlignment(_codeInfo.getStackAlignment());
// Allocate space for function arguments.
func->_args = nullptr;
if (func->getArgCount() != 0) {
func->_args = _cbHeap.allocT<VirtReg*>(func->getArgCount() * sizeof(VirtReg*));
if (!func->_args) goto _NoMemory;
::memset(func->_args, 0, func->getArgCount() * sizeof(VirtReg*));
}
return func;
_NoMemory:
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
return nullptr;
}
CCFunc* CodeCompiler::addFunc(CCFunc* func) {
ASMJIT_ASSERT(_func == nullptr);
_func = func;
addNode(func); // Function node.
CBNode* cursor = getCursor(); // {CURSOR}.
addNode(func->getExitNode()); // Function exit label.
addNode(func->getEnd()); // Function end marker.
_setCursor(cursor);
return func;
}
CCFunc* CodeCompiler::addFunc(const FuncSignature& sign) {
CCFunc* func = newFunc(sign);
if (!func) {
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
return nullptr;
}
return addFunc(func);
}
CBSentinel* CodeCompiler::endFunc() {
CCFunc* func = getFunc();
if (!func) {
// TODO:
return nullptr;
}
// Add the local constant pool at the end of the function (if exists).
if (_localConstPool) {
setCursor(func->getEnd()->getPrev());
addNode(_localConstPool);
_localConstPool = nullptr;
}
// Mark as finished.
func->_isFinished = true;
_func = nullptr;
CBSentinel* end = func->getEnd();
setCursor(end);
return end;
}
// ============================================================================
// [asmjit::CodeCompiler - Ret]
// ============================================================================
CCFuncRet* CodeCompiler::newRet(const Operand_& o0, const Operand_& o1) noexcept {
CCFuncRet* node = newNodeT<CCFuncRet>(o0, o1);
if (!node) {
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
return nullptr;
}
return node;
}
CCFuncRet* CodeCompiler::addRet(const Operand_& o0, const Operand_& o1) noexcept {
CCFuncRet* node = newRet(o0, o1);
if (!node) return nullptr;
return static_cast<CCFuncRet*>(addNode(node));
}
// ============================================================================
// [asmjit::CodeCompiler - Call]
// ============================================================================
CCFuncCall* CodeCompiler::newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept {
Error err;
uint32_t nArgs;
CCFuncCall* node = _cbHeap.allocT<CCFuncCall>(sizeof(CCFuncCall) + sizeof(Operand));
Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CCFuncCall));
if (ASMJIT_UNLIKELY(!node))
goto _NoMemory;
opArray[0].copyFrom(o0);
new (node) CCFuncCall(this, instId, 0, opArray, 1);
if ((err = node->getDetail().init(sign)) != kErrorOk) {
setLastError(err);
return nullptr;
}
// If there are no arguments skip the allocation.
if ((nArgs = sign.getArgCount()) == 0)
return node;
node->_args = static_cast<Operand*>(_cbHeap.alloc(nArgs * sizeof(Operand)));
if (!node->_args) goto _NoMemory;
::memset(node->_args, 0, nArgs * sizeof(Operand));
return node;
_NoMemory:
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
return nullptr;
}
CCFuncCall* CodeCompiler::addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept {
CCFuncCall* node = newCall(instId, o0, sign);
if (!node) return nullptr;
return static_cast<CCFuncCall*>(addNode(node));
}
// ============================================================================
// [asmjit::CodeCompiler - Vars]
// ============================================================================
Error CodeCompiler::setArg(uint32_t argIndex, const Reg& r) {
CCFunc* func = getFunc();
if (!func)
return setLastError(DebugUtils::errored(kErrorInvalidState));
if (!isVirtRegValid(r))
return setLastError(DebugUtils::errored(kErrorInvalidVirtId));
VirtReg* vr = getVirtReg(r);
func->setArg(argIndex, vr);
return kErrorOk;
}
// ============================================================================
// [asmjit::CodeCompiler - Hint]
// ============================================================================
Error CodeCompiler::_hint(Reg& r, uint32_t hint, uint32_t value) {
if (!r.isVirtReg()) return kErrorOk;
CCHint* node = newHintNode(r, hint, value);
if (!node) return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
addNode(node);
return kErrorOk;
}
// ============================================================================
// [asmjit::CodeCompiler - Vars]
// ============================================================================
VirtReg* CodeCompiler::newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept {
size_t index = _vRegArray.getLength();
if (ASMJIT_UNLIKELY(index > Operand::kPackedIdCount))
return nullptr;
VirtReg* vreg;
if (_vRegArray.willGrow(&_cbHeap, 1) != kErrorOk || !(vreg = _vRegZone.allocZeroedT<VirtReg>()))
return nullptr;
vreg->_id = Operand::packId(static_cast<uint32_t>(index));
vreg->_regInfo._signature = signature;
vreg->_name = noName;
#if !defined(ASMJIT_DISABLE_LOGGING)
if (name && name[0] != '\0')
vreg->_name = static_cast<char*>(_cbDataZone.dup(name, ::strlen(name), true));
#endif // !ASMJIT_DISABLE_LOGGING
vreg->_size = TypeId::sizeOf(typeId);
vreg->_typeId = typeId;
vreg->_alignment = static_cast<uint8_t>(std::min<uint32_t>(vreg->_size, 64));
vreg->_priority = 10;
// The following are only used by `RAPass`.
vreg->_raId = kInvalidValue;
vreg->_state = VirtReg::kStateNone;
vreg->_physId = Globals::kInvalidRegId;
_vRegArray.appendUnsafe(vreg);
return vreg;
}
Error CodeCompiler::_newReg(Reg& out, uint32_t typeId, const char* name) {
RegInfo regInfo;
Error err = ArchUtils::typeIdToRegInfo(getArchType(), typeId, regInfo);
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
VirtReg* vReg = newVirtReg(typeId, regInfo.getSignature(), name);
if (ASMJIT_UNLIKELY(!vReg)) {
out.reset();
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
}
out._initReg(regInfo.getSignature(), vReg->getId());
return kErrorOk;
}
Error CodeCompiler::_newReg(Reg& out, uint32_t typeId, const char* nameFmt, va_list ap) {
StringBuilderTmp<256> sb;
sb.appendFormatVA(nameFmt, ap);
return _newReg(out, typeId, sb.getData());
}
Error CodeCompiler::_newReg(Reg& out, const Reg& ref, const char* name) {
RegInfo regInfo;
uint32_t typeId;
if (isVirtRegValid(ref)) {
VirtReg* vRef = getVirtReg(ref);
typeId = vRef->getTypeId();
// NOTE: It's possible to cast one register type to another if it's the
// same register kind. However, VirtReg always contains the TypeId that
// was used to create the register. This means that in some cases we may
// end up having different size of `ref` and `vRef`. In such case we
// adjust the TypeId to match the `ref` register type instead of the
// original register type, which should be the expected behavior.
uint32_t typeSize = TypeId::sizeOf(typeId);
uint32_t refSize = ref.getSize();
if (typeSize != refSize) {
if (TypeId::isInt(typeId)) {
// GP register - change TypeId to match `ref`, but keep sign of `vRef`.
switch (refSize) {
case 1: typeId = TypeId::kI8 | (typeId & 1); break;
case 2: typeId = TypeId::kI16 | (typeId & 1); break;
case 4: typeId = TypeId::kI32 | (typeId & 1); break;
case 8: typeId = TypeId::kI64 | (typeId & 1); break;
default: typeId = TypeId::kVoid; break;
}
}
else if (TypeId::isMmx(typeId)) {
// MMX register - always use 64-bit.
typeId = TypeId::kMmx64;
}
else if (TypeId::isMask(typeId)) {
// Mask register - change TypeId to match `ref` size.
switch (refSize) {
case 1: typeId = TypeId::kMask8; break;
case 2: typeId = TypeId::kMask16; break;
case 4: typeId = TypeId::kMask32; break;
case 8: typeId = TypeId::kMask64; break;
default: typeId = TypeId::kVoid; break;
}
}
else {
// VEC register - change TypeId to match `ref` size, keep vector metadata.
uint32_t elementTypeId = TypeId::elementOf(typeId);
switch (refSize) {
case 16: typeId = TypeId::_kVec128Start + (elementTypeId - TypeId::kI8); break;
case 32: typeId = TypeId::_kVec256Start + (elementTypeId - TypeId::kI8); break;
case 64: typeId = TypeId::_kVec512Start + (elementTypeId - TypeId::kI8); break;
default: typeId = TypeId::kVoid; break;
}
}
if (typeId == TypeId::kVoid)
return setLastError(DebugUtils::errored(kErrorInvalidState));
}
}
else {
typeId = ref.getType();
}
Error err = ArchUtils::typeIdToRegInfo(getArchType(), typeId, regInfo);
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
VirtReg* vReg = newVirtReg(typeId, regInfo.getSignature(), name);
if (ASMJIT_UNLIKELY(!vReg)) {
out.reset();
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
}
out._initReg(regInfo.getSignature(), vReg->getId());
return kErrorOk;
}
Error CodeCompiler::_newReg(Reg& out, const Reg& ref, const char* nameFmt, va_list ap) {
StringBuilderTmp<256> sb;
sb.appendFormatVA(nameFmt, ap);
return _newReg(out, ref, sb.getData());
}
Error CodeCompiler::_newStack(Mem& out, uint32_t size, uint32_t alignment, const char* name) {
if (size == 0)
return setLastError(DebugUtils::errored(kErrorInvalidArgument));
if (alignment == 0) alignment = 1;
if (!Utils::isPowerOf2(alignment))
return setLastError(DebugUtils::errored(kErrorInvalidArgument));
if (alignment > 64) alignment = 64;
VirtReg* vReg = newVirtReg(0, 0, name);
if (ASMJIT_UNLIKELY(!vReg)) {
out.reset();
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
}
vReg->_size = size;
vReg->_isStack = true;
vReg->_alignment = static_cast<uint8_t>(alignment);
// Set the memory operand to GPD/GPQ and its id to VirtReg.
out = Mem(Init, _nativeGpReg.getType(), vReg->getId(), Reg::kRegNone, kInvalidValue, 0, 0, Mem::kSignatureMemRegHomeFlag);
return kErrorOk;
}
Error CodeCompiler::_newConst(Mem& out, uint32_t scope, const void* data, size_t size) {
CBConstPool** pPool;
if (scope == kConstScopeLocal)
pPool = &_localConstPool;
else if (scope == kConstScopeGlobal)
pPool = &_globalConstPool;
else
return setLastError(DebugUtils::errored(kErrorInvalidArgument));
if (!*pPool && !(*pPool = newConstPool()))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
CBConstPool* pool = *pPool;
size_t off;
Error err = pool->add(data, size, off);
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
out = Mem(Init,
Label::kLabelTag, // Base type.
pool->getId(), // Base id.
0, // Index type.
kInvalidValue, // Index id.
static_cast<int32_t>(off), // Offset.
static_cast<uint32_t>(size), // Size.
0); // Flags.
return kErrorOk;
}
Error CodeCompiler::alloc(Reg& reg) {
if (!reg.isVirtReg()) return kErrorOk;
return _hint(reg, CCHint::kHintAlloc, kInvalidValue);
}
Error CodeCompiler::alloc(Reg& reg, uint32_t physId) {
if (!reg.isVirtReg()) return kErrorOk;
return _hint(reg, CCHint::kHintAlloc, physId);
}
Error CodeCompiler::alloc(Reg& reg, const Reg& physReg) {
if (!reg.isVirtReg()) return kErrorOk;
return _hint(reg, CCHint::kHintAlloc, physReg.getId());
}
Error CodeCompiler::save(Reg& reg) {
if (!reg.isVirtReg()) return kErrorOk;
return _hint(reg, CCHint::kHintSave, kInvalidValue);
}
Error CodeCompiler::spill(Reg& reg) {
if (!reg.isVirtReg()) return kErrorOk;
return _hint(reg, CCHint::kHintSpill, kInvalidValue);
}
Error CodeCompiler::unuse(Reg& reg) {
if (!reg.isVirtReg()) return kErrorOk;
return _hint(reg, CCHint::kHintUnuse, kInvalidValue);
}
uint32_t CodeCompiler::getPriority(Reg& reg) const {
if (!reg.isVirtReg()) return 0;
return getVirtRegById(reg.getId())->getPriority();
}
void CodeCompiler::setPriority(Reg& reg, uint32_t priority) {
if (!reg.isVirtReg()) return;
if (priority > 255) priority = 255;
VirtReg* vreg = getVirtRegById(reg.getId());
if (vreg) vreg->_priority = static_cast<uint8_t>(priority);
}
bool CodeCompiler::getSaveOnUnuse(Reg& reg) const {
if (!reg.isVirtReg()) return false;
VirtReg* vreg = getVirtRegById(reg.getId());
return static_cast<bool>(vreg->_saveOnUnuse);
}
void CodeCompiler::setSaveOnUnuse(Reg& reg, bool value) {
if (!reg.isVirtReg()) return;
VirtReg* vreg = getVirtRegById(reg.getId());
if (!vreg) return;
vreg->_saveOnUnuse = value;
}
void CodeCompiler::rename(Reg& reg, const char* fmt, ...) {
if (!reg.isVirtReg()) return;
VirtReg* vreg = getVirtRegById(reg.getId());
if (!vreg) return;
vreg->_name = noName;
if (fmt && fmt[0] != '\0') {
char buf[64];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap);
buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0';
vreg->_name = static_cast<char*>(_cbDataZone.dup(buf, ::strlen(buf), true));
va_end(ap);
}
}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER

View File

@ -1,738 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CODECOMPILER_H
#define _ASMJIT_BASE_CODECOMPILER_H
#include "../asmjit_build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies]
#include "../base/assembler.h"
#include "../base/codebuilder.h"
#include "../base/constpool.h"
#include "../base/func.h"
#include "../base/operand.h"
#include "../base/utils.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [Forward Declarations]
// ============================================================================
struct VirtReg;
struct TiedReg;
struct RAState;
struct RACell;
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [asmjit::ConstScope]
// ============================================================================
//! Scope of the constant.
ASMJIT_ENUM(ConstScope) {
//! Local constant, always embedded right after the current function.
kConstScopeLocal = 0,
//! Global constant, embedded at the end of the currently compiled code.
kConstScopeGlobal = 1
};
// ============================================================================
// [asmjit::VirtReg]
// ============================================================================
//! Virtual register data (CodeCompiler).
struct VirtReg {
//! A state of a virtual register (used during register allocation).
ASMJIT_ENUM(State) {
kStateNone = 0, //!< Not allocated, not used.
kStateReg = 1, //!< Allocated in register.
kStateMem = 2 //!< Allocated in memory or spilled.
};
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the virtual-register id.
ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
//! Get virtual-register's name.
ASMJIT_INLINE const char* getName() const noexcept { return _name; }
//! Get a physical register type.
ASMJIT_INLINE uint32_t getType() const noexcept { return _regInfo.getType(); }
//! Get a physical register kind.
ASMJIT_INLINE uint32_t getKind() const noexcept { return _regInfo.getKind(); }
//! Get a physical register size.
ASMJIT_INLINE uint32_t getRegSize() const noexcept { return _regInfo.getSize(); }
//! Get a register signature of this virtual register.
ASMJIT_INLINE uint32_t getSignature() const noexcept { return _regInfo.getSignature(); }
//! Get a register's type-id, see \ref TypeId.
ASMJIT_INLINE uint32_t getTypeId() const noexcept { return _typeId; }
//! Get virtual-register's size.
ASMJIT_INLINE uint32_t getSize() const noexcept { return _size; }
//! Get virtual-register's alignment.
ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; }
//! Get the virtual-register priority, used by compiler to decide which variable to spill.
ASMJIT_INLINE uint32_t getPriority() const noexcept { return _priority; }
//! Set the virtual-register priority.
ASMJIT_INLINE void setPriority(uint32_t priority) noexcept {
ASMJIT_ASSERT(priority <= 0xFF);
_priority = static_cast<uint8_t>(priority);
}
//! Get variable state, only used by `RAPass`.
ASMJIT_INLINE uint32_t getState() const noexcept { return _state; }
//! Set variable state, only used by `RAPass`.
ASMJIT_INLINE void setState(uint32_t state) {
ASMJIT_ASSERT(state <= 0xFF);
_state = static_cast<uint8_t>(state);
}
//! Get register index.
ASMJIT_INLINE uint32_t getPhysId() const noexcept { return _physId; }
//! Set register index.
ASMJIT_INLINE void setPhysId(uint32_t physId) {
ASMJIT_ASSERT(physId <= Globals::kInvalidRegId);
_physId = static_cast<uint8_t>(physId);
}
//! Reset register index.
ASMJIT_INLINE void resetPhysId() {
_physId = static_cast<uint8_t>(Globals::kInvalidRegId);
}
//! Get home registers mask.
ASMJIT_INLINE uint32_t getHomeMask() const { return _homeMask; }
//! Add a home register index to the home registers mask.
ASMJIT_INLINE void addHomeId(uint32_t physId) { _homeMask |= Utils::mask(physId); }
ASMJIT_INLINE bool isFixed() const noexcept { return static_cast<bool>(_isFixed); }
//! Get whether the VirtReg is only memory allocated on the stack.
ASMJIT_INLINE bool isStack() const noexcept { return static_cast<bool>(_isStack); }
//! Get whether to save variable when it's unused (spill).
ASMJIT_INLINE bool saveOnUnuse() const noexcept { return static_cast<bool>(_saveOnUnuse); }
//! Get whether the variable was changed.
ASMJIT_INLINE bool isModified() const noexcept { return static_cast<bool>(_modified); }
//! Set whether the variable was changed.
ASMJIT_INLINE void setModified(bool modified) noexcept { _modified = modified; }
//! Get home memory offset.
ASMJIT_INLINE int32_t getMemOffset() const noexcept { return _memOffset; }
//! Set home memory offset.
ASMJIT_INLINE void setMemOffset(int32_t offset) noexcept { _memOffset = offset; }
//! Get home memory cell.
ASMJIT_INLINE RACell* getMemCell() const noexcept { return _memCell; }
//! Set home memory cell.
ASMJIT_INLINE void setMemCell(RACell* cell) noexcept { _memCell = cell; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint32_t _id; //!< Virtual register id.
RegInfo _regInfo; //!< Physical register info & signature.
const char* _name; //!< Virtual name (user provided).
uint32_t _size; //!< Virtual size (can be smaller than `regInfo._size`).
uint8_t _typeId; //!< Type-id.
uint8_t _alignment; //!< Register's natural alignment (for spilling).
uint8_t _priority; //!< Allocation priority (hint for RAPass that can be ignored).
uint8_t _isFixed : 1; //!< True if this is a fixed register, never reallocated.
uint8_t _isStack : 1; //!< True if the virtual register is only used as a stack.
uint8_t _isMaterialized : 1; //!< Register is constant that is easily created by a single instruction.
uint8_t _saveOnUnuse : 1; //!< Save on unuse (at end of the variable scope).
// -------------------------------------------------------------------------
// The following members are used exclusively by RAPass. They are initialized
// when the VirtReg is created and then changed during RAPass.
// -------------------------------------------------------------------------
uint32_t _raId; //!< Register allocator work-id (used by RAPass).
int32_t _memOffset; //!< Home memory offset.
uint32_t _homeMask; //!< Mask of all registers variable has been allocated to.
uint8_t _state; //!< Variable state (connected with actual `RAState)`.
uint8_t _physId; //!< Actual register index (only used by `RAPass)`, during translate.
uint8_t _modified; //!< Whether variable was changed (connected with actual `RAState)`.
RACell* _memCell; //!< Home memory cell, used by `RAPass` (initially nullptr).
//! Temporary link to TiedReg* used by the `RAPass` used in
//! various phases, but always set back to nullptr when finished.
//!
//! This temporary data is designed to be used by algorithms that need to
//! store some data into variables themselves during compilation. But it's
//! expected that after variable is compiled & translated the data is set
//! back to zero/null. Initial value is nullptr.
TiedReg* _tied;
};
// ============================================================================
// [asmjit::CCHint]
// ============================================================================
//! Hint for register allocator (CodeCompiler).
class CCHint : public CBNode {
public:
ASMJIT_NONCOPYABLE(CCHint)
//! Hint type.
ASMJIT_ENUM(Hint) {
//! Alloc to physical reg.
kHintAlloc = 0,
//! Spill to memory.
kHintSpill = 1,
//! Save if modified.
kHintSave = 2,
//! Save if modified and mark it as unused.
kHintSaveAndUnuse = 3,
//! Mark as unused.
kHintUnuse = 4
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CCHint` instance.
ASMJIT_INLINE CCHint(CodeBuilder* cb, VirtReg* vreg, uint32_t hint, uint32_t value) noexcept : CBNode(cb, kNodeHint) {
orFlags(kFlagIsRemovable | kFlagIsInformative);
_vreg = vreg;
_hint = hint;
_value = value;
}
//! Destroy the `CCHint` instance (NEVER CALLED).
ASMJIT_INLINE ~CCHint() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get variable.
ASMJIT_INLINE VirtReg* getVReg() const noexcept { return _vreg; }
//! Get hint it, see \ref Hint.
ASMJIT_INLINE uint32_t getHint() const noexcept { return _hint; }
//! Set hint it, see \ref Hint.
ASMJIT_INLINE void setHint(uint32_t hint) noexcept { _hint = hint; }
//! Get hint value.
ASMJIT_INLINE uint32_t getValue() const noexcept { return _value; }
//! Set hint value.
ASMJIT_INLINE void setValue(uint32_t value) noexcept { _value = value; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Variable.
VirtReg* _vreg;
//! Hint id.
uint32_t _hint;
//! Value.
uint32_t _value;
};
// ============================================================================
// [asmjit::CCFunc]
// ============================================================================
//! Function entry (CodeCompiler).
class CCFunc : public CBLabel {
public:
ASMJIT_NONCOPYABLE(CCFunc)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CCFunc` instance.
//!
//! Always use `CodeCompiler::addFunc()` to create \ref CCFunc.
ASMJIT_INLINE CCFunc(CodeBuilder* cb) noexcept
: CBLabel(cb),
_funcDetail(),
_frameInfo(),
_exitNode(nullptr),
_end(nullptr),
_args(nullptr),
_isFinished(false) {
_type = kNodeFunc;
}
//! Destroy the `CCFunc` instance (NEVER CALLED).
ASMJIT_INLINE ~CCFunc() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get function exit `CBLabel`.
ASMJIT_INLINE CBLabel* getExitNode() const noexcept { return _exitNode; }
//! Get function exit label.
ASMJIT_INLINE Label getExitLabel() const noexcept { return _exitNode->getLabel(); }
//! Get "End of Func" sentinel.
ASMJIT_INLINE CBSentinel* getEnd() const noexcept { return _end; }
//! Get function declaration.
ASMJIT_INLINE FuncDetail& getDetail() noexcept { return _funcDetail; }
//! Get function declaration.
ASMJIT_INLINE const FuncDetail& getDetail() const noexcept { return _funcDetail; }
//! Get function declaration.
ASMJIT_INLINE FuncFrameInfo& getFrameInfo() noexcept { return _frameInfo; }
//! Get function declaration.
ASMJIT_INLINE const FuncFrameInfo& getFrameInfo() const noexcept { return _frameInfo; }
//! Get arguments count.
ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _funcDetail.getArgCount(); }
//! Get returns count.
ASMJIT_INLINE uint32_t getRetCount() const noexcept { return _funcDetail.getRetCount(); }
//! Get arguments list.
ASMJIT_INLINE VirtReg** getArgs() const noexcept { return _args; }
//! Get argument at `i`.
ASMJIT_INLINE VirtReg* getArg(uint32_t i) const noexcept {
ASMJIT_ASSERT(i < getArgCount());
return _args[i];
}
//! Set argument at `i`.
ASMJIT_INLINE void setArg(uint32_t i, VirtReg* vreg) noexcept {
ASMJIT_ASSERT(i < getArgCount());
_args[i] = vreg;
}
//! Reset argument at `i`.
ASMJIT_INLINE void resetArg(uint32_t i) noexcept {
ASMJIT_ASSERT(i < getArgCount());
_args[i] = nullptr;
}
ASMJIT_INLINE uint32_t getAttributes() const noexcept { return _frameInfo.getAttributes(); }
ASMJIT_INLINE void addAttributes(uint32_t attrs) noexcept { _frameInfo.addAttributes(attrs); }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
FuncDetail _funcDetail; //!< Function detail.
FuncFrameInfo _frameInfo; //!< Function frame information.
CBLabel* _exitNode; //!< Function exit.
CBSentinel* _end; //!< Function end.
VirtReg** _args; //!< Arguments array as `VirtReg`.
//! Function was finished by `Compiler::endFunc()`.
uint8_t _isFinished;
};
// ============================================================================
// [asmjit::CCFuncRet]
// ============================================================================
//! Function return (CodeCompiler).
class CCFuncRet : public CBNode {
public:
ASMJIT_NONCOPYABLE(CCFuncRet)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CCFuncRet` instance.
ASMJIT_INLINE CCFuncRet(CodeBuilder* cb, const Operand_& o0, const Operand_& o1) noexcept : CBNode(cb, kNodeFuncExit) {
orFlags(kFlagIsRet);
_ret[0].copyFrom(o0);
_ret[1].copyFrom(o1);
}
//! Destroy the `CCFuncRet` instance (NEVER CALLED).
ASMJIT_INLINE ~CCFuncRet() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the first return operand.
ASMJIT_INLINE Operand& getFirst() noexcept { return static_cast<Operand&>(_ret[0]); }
//! \overload
ASMJIT_INLINE const Operand& getFirst() const noexcept { return static_cast<const Operand&>(_ret[0]); }
//! Get the second return operand.
ASMJIT_INLINE Operand& getSecond() noexcept { return static_cast<Operand&>(_ret[1]); }
//! \overload
ASMJIT_INLINE const Operand& getSecond() const noexcept { return static_cast<const Operand&>(_ret[1]); }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Return operands.
Operand_ _ret[2];
};
// ============================================================================
// [asmjit::CCFuncCall]
// ============================================================================
//! Function call (CodeCompiler).
class CCFuncCall : public CBInst {
public:
ASMJIT_NONCOPYABLE(CCFuncCall)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CCFuncCall` instance.
ASMJIT_INLINE CCFuncCall(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept
: CBInst(cb, instId, options, opArray, opCount),
_funcDetail(),
_args(nullptr) {
_type = kNodeFuncCall;
_ret[0].reset();
_ret[1].reset();
orFlags(kFlagIsRemovable);
}
//! Destroy the `CCFuncCall` instance (NEVER CALLED).
ASMJIT_INLINE ~CCFuncCall() noexcept {}
// --------------------------------------------------------------------------
// [Signature]
// --------------------------------------------------------------------------
//! Set function signature.
ASMJIT_INLINE Error setSignature(const FuncSignature& sign) noexcept {
return _funcDetail.init(sign);
}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get function declaration.
ASMJIT_INLINE FuncDetail& getDetail() noexcept { return _funcDetail; }
//! Get function declaration.
ASMJIT_INLINE const FuncDetail& getDetail() const noexcept { return _funcDetail; }
//! Get target operand.
ASMJIT_INLINE Operand& getTarget() noexcept { return static_cast<Operand&>(_opArray[0]); }
//! \overload
ASMJIT_INLINE const Operand& getTarget() const noexcept { return static_cast<const Operand&>(_opArray[0]); }
//! Get return at `i`.
ASMJIT_INLINE Operand& getRet(uint32_t i = 0) noexcept {
ASMJIT_ASSERT(i < 2);
return static_cast<Operand&>(_ret[i]);
}
//! \overload
ASMJIT_INLINE const Operand& getRet(uint32_t i = 0) const noexcept {
ASMJIT_ASSERT(i < 2);
return static_cast<const Operand&>(_ret[i]);
}
//! Get argument at `i`.
ASMJIT_INLINE Operand& getArg(uint32_t i) noexcept {
ASMJIT_ASSERT(i < kFuncArgCountLoHi);
return static_cast<Operand&>(_args[i]);
}
//! \overload
ASMJIT_INLINE const Operand& getArg(uint32_t i) const noexcept {
ASMJIT_ASSERT(i < kFuncArgCountLoHi);
return static_cast<const Operand&>(_args[i]);
}
//! Set argument at `i` to `op`.
ASMJIT_API bool _setArg(uint32_t i, const Operand_& op) noexcept;
//! Set return at `i` to `op`.
ASMJIT_API bool _setRet(uint32_t i, const Operand_& op) noexcept;
//! Set argument at `i` to `reg`.
ASMJIT_INLINE bool setArg(uint32_t i, const Reg& reg) noexcept { return _setArg(i, reg); }
//! Set argument at `i` to `imm`.
ASMJIT_INLINE bool setArg(uint32_t i, const Imm& imm) noexcept { return _setArg(i, imm); }
//! Set return at `i` to `var`.
ASMJIT_INLINE bool setRet(uint32_t i, const Reg& reg) noexcept { return _setRet(i, reg); }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
FuncDetail _funcDetail; //!< Function detail.
Operand_ _ret[2]; //!< Return.
Operand_* _args; //!< Arguments.
};
// ============================================================================
// [asmjit::CCPushArg]
// ============================================================================
//! Push argument before a function call (CodeCompiler).
class CCPushArg : public CBNode {
public:
ASMJIT_NONCOPYABLE(CCPushArg)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CCPushArg` instance.
ASMJIT_INLINE CCPushArg(CodeBuilder* cb, CCFuncCall* call, VirtReg* src, VirtReg* cvt) noexcept
: CBNode(cb, kNodePushArg),
_call(call),
_src(src),
_cvt(cvt),
_args(0) {
orFlags(kFlagIsRemovable);
}
//! Destroy the `CCPushArg` instance.
ASMJIT_INLINE ~CCPushArg() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the associated function-call.
ASMJIT_INLINE CCFuncCall* getCall() const noexcept { return _call; }
//! Get source variable.
ASMJIT_INLINE VirtReg* getSrcReg() const noexcept { return _src; }
//! Get conversion variable.
ASMJIT_INLINE VirtReg* getCvtReg() const noexcept { return _cvt; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
CCFuncCall* _call; //!< Associated `CCFuncCall`.
VirtReg* _src; //!< Source variable.
VirtReg* _cvt; //!< Temporary variable used for conversion (or null).
uint32_t _args; //!< Affected arguments bit-array.
};
// ============================================================================
// [asmjit::CodeCompiler]
// ============================================================================
//! Code emitter that uses virtual registers and performs register allocation.
//!
//! Compiler is a high-level code-generation tool that provides register
//! allocation and automatic handling of function calling conventions. It was
//! primarily designed for merging multiple parts of code into a function
//! without worrying about registers and function calling conventions.
//!
//! CodeCompiler can be used, with a minimum effort, to handle 32-bit and 64-bit
//! code at the same time.
//!
//! CodeCompiler is based on CodeBuilder and contains all the features it
//! provides. It means that the code it stores can be modified (removed, added,
//! injected) and analyzed. When the code is finalized the compiler can emit
//! the code into an Assembler to translate the abstract representation into a
//! machine code.
class ASMJIT_VIRTAPI CodeCompiler : public CodeBuilder {
public:
ASMJIT_NONCOPYABLE(CodeCompiler)
typedef CodeBuilder Base;
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CodeCompiler` instance.
ASMJIT_API CodeCompiler() noexcept;
//! Destroy the `CodeCompiler` instance.
ASMJIT_API virtual ~CodeCompiler() noexcept;
// --------------------------------------------------------------------------
// [Events]
// --------------------------------------------------------------------------
ASMJIT_API virtual Error onAttach(CodeHolder* code) noexcept override;
ASMJIT_API virtual Error onDetach(CodeHolder* code) noexcept override;
// --------------------------------------------------------------------------
// [Node-Factory]
// --------------------------------------------------------------------------
//! \internal
//!
//! Create a new `CCHint`.
ASMJIT_API CCHint* newHintNode(Reg& reg, uint32_t hint, uint32_t value) noexcept;
// --------------------------------------------------------------------------
// [Func]
// --------------------------------------------------------------------------
//! Get the current function.
ASMJIT_INLINE CCFunc* getFunc() const noexcept { return _func; }
//! Create a new `CCFunc`.
ASMJIT_API CCFunc* newFunc(const FuncSignature& sign) noexcept;
//! Add a function `node` to the stream.
ASMJIT_API CCFunc* addFunc(CCFunc* func);
//! Add a new function.
ASMJIT_API CCFunc* addFunc(const FuncSignature& sign);
//! Emit a sentinel that marks the end of the current function.
ASMJIT_API CBSentinel* endFunc();
// --------------------------------------------------------------------------
// [Ret]
// --------------------------------------------------------------------------
//! Create a new `CCFuncRet`.
ASMJIT_API CCFuncRet* newRet(const Operand_& o0, const Operand_& o1) noexcept;
//! Add a new `CCFuncRet`.
ASMJIT_API CCFuncRet* addRet(const Operand_& o0, const Operand_& o1) noexcept;
// --------------------------------------------------------------------------
// [Call]
// --------------------------------------------------------------------------
//! Create a new `CCFuncCall`.
ASMJIT_API CCFuncCall* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept;
//! Add a new `CCFuncCall`.
ASMJIT_API CCFuncCall* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept;
// --------------------------------------------------------------------------
// [Args]
// --------------------------------------------------------------------------
//! Set a function argument at `argIndex` to `reg`.
ASMJIT_API Error setArg(uint32_t argIndex, const Reg& reg);
// --------------------------------------------------------------------------
// [Hint]
// --------------------------------------------------------------------------
//! Emit a new hint (purely informational node).
ASMJIT_API Error _hint(Reg& reg, uint32_t hint, uint32_t value);
// --------------------------------------------------------------------------
// [VirtReg / Stack]
// --------------------------------------------------------------------------
//! Create a new virtual register representing the given `vti` and `signature`.
//!
//! This function accepts either register type representing a machine-specific
//! register, like `X86Reg`, or RegTag representation, which represents
//! machine independent register, and from the machine-specific register
//! is deduced.
ASMJIT_API VirtReg* newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept;
ASMJIT_API Error _newReg(Reg& out, uint32_t typeId, const char* name);
ASMJIT_API Error _newReg(Reg& out, uint32_t typeId, const char* nameFmt, va_list ap);
ASMJIT_API Error _newReg(Reg& out, const Reg& ref, const char* name);
ASMJIT_API Error _newReg(Reg& out, const Reg& ref, const char* nameFmt, va_list ap);
ASMJIT_API Error _newStack(Mem& out, uint32_t size, uint32_t alignment, const char* name);
ASMJIT_API Error _newConst(Mem& out, uint32_t scope, const void* data, size_t size);
// --------------------------------------------------------------------------
// [VirtReg]
// --------------------------------------------------------------------------
//! Get whether the virtual register `r` is valid.
ASMJIT_INLINE bool isVirtRegValid(const Reg& reg) const noexcept {
return isVirtRegValid(reg.getId());
}
//! \overload
ASMJIT_INLINE bool isVirtRegValid(uint32_t id) const noexcept {
size_t index = Operand::unpackId(id);
return index < _vRegArray.getLength();
}
//! Get \ref VirtReg associated with the given `r`.
ASMJIT_INLINE VirtReg* getVirtReg(const Reg& reg) const noexcept {
return getVirtRegById(reg.getId());
}
//! Get \ref VirtReg associated with the given `id`.
ASMJIT_INLINE VirtReg* getVirtRegById(uint32_t id) const noexcept {
ASMJIT_ASSERT(id != kInvalidValue);
size_t index = Operand::unpackId(id);
ASMJIT_ASSERT(index < _vRegArray.getLength());
return _vRegArray[index];
}
//! Get an array of all virtual registers managed by CodeCompiler.
ASMJIT_INLINE const ZoneVector<VirtReg*>& getVirtRegArray() const noexcept { return _vRegArray; }
//! Alloc a virtual register `reg`.
ASMJIT_API Error alloc(Reg& reg);
//! Alloc a virtual register `reg` using `physId` as a register id.
ASMJIT_API Error alloc(Reg& reg, uint32_t physId);
//! Alloc a virtual register `reg` using `ref` as a register operand.
ASMJIT_API Error alloc(Reg& reg, const Reg& ref);
//! Spill a virtual register `reg`.
ASMJIT_API Error spill(Reg& reg);
//! Save a virtual register `reg` if the status is `modified` at this point.
ASMJIT_API Error save(Reg& reg);
//! Unuse a virtual register `reg`.
ASMJIT_API Error unuse(Reg& reg);
//! Get priority of a virtual register `reg`.
ASMJIT_API uint32_t getPriority(Reg& reg) const;
//! Set priority of variable `reg` to `priority`.
ASMJIT_API void setPriority(Reg& reg, uint32_t priority);
//! Get save-on-unuse `reg` property.
ASMJIT_API bool getSaveOnUnuse(Reg& reg) const;
//! Set save-on-unuse `reg` property to `value`.
ASMJIT_API void setSaveOnUnuse(Reg& reg, bool value);
//! Rename variable `reg` to `name`.
//!
//! NOTE: Only new name will appear in the logger.
ASMJIT_API void rename(Reg& reg, const char* fmt, ...);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
CCFunc* _func; //!< Current function.
Zone _vRegZone; //!< Allocates \ref VirtReg objects.
ZoneVector<VirtReg*> _vRegArray; //!< Stores array of \ref VirtReg pointers.
CBConstPool* _localConstPool; //!< Local constant pool, flushed at the end of each function.
CBConstPool* _globalConstPool; //!< Global constant pool, flushed at the end of the compilation.
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER
#endif // _ASMJIT_BASE_CODECOMPILER_H

View File

@ -1,236 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies]
#include "../base/assembler.h"
#include "../base/utils.h"
#include "../base/vmem.h"
#if defined(ASMJIT_BUILD_X86)
#include "../x86/x86inst.h"
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
#include "../arm/arminst.h"
#endif // ASMJIT_BUILD_ARM
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::CodeEmitter - Construction / Destruction]
// ============================================================================
CodeEmitter::CodeEmitter(uint32_t type) noexcept
: _codeInfo(),
_code(nullptr),
_nextEmitter(nullptr),
_type(static_cast<uint8_t>(type)),
_destroyed(false),
_finalized(false),
_reserved(false),
_lastError(kErrorNotInitialized),
_privateData(0),
_globalHints(0),
_globalOptions(kOptionMaybeFailureCase),
_options(0),
_extraReg(),
_inlineComment(nullptr),
_none(),
_nativeGpReg(),
_nativeGpArray(nullptr) {}
CodeEmitter::~CodeEmitter() noexcept {
if (_code) {
_destroyed = true;
_code->detach(this);
}
}
// ============================================================================
// [asmjit::CodeEmitter - Events]
// ============================================================================
Error CodeEmitter::onAttach(CodeHolder* code) noexcept {
_codeInfo = code->getCodeInfo();
_lastError = kErrorOk;
_globalHints = code->getGlobalHints();
_globalOptions = code->getGlobalOptions();
return kErrorOk;
}
Error CodeEmitter::onDetach(CodeHolder* code) noexcept {
_codeInfo.reset();
_finalized = false;
_lastError = kErrorNotInitialized;
_privateData = 0;
_globalHints = 0;
_globalOptions = kOptionMaybeFailureCase;
_options = 0;
_extraReg.reset();
_inlineComment = nullptr;
_nativeGpReg.reset();
_nativeGpArray = nullptr;
return kErrorOk;
}
// ============================================================================
// [asmjit::CodeEmitter - Code-Generation]
// ============================================================================
Error CodeEmitter::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
const Operand_* op = opArray;
switch (opCount) {
case 0: return _emit(instId, _none, _none, _none, _none);
case 1: return _emit(instId, op[0], _none, _none, _none);
case 2: return _emit(instId, op[0], op[1], _none, _none);
case 3: return _emit(instId, op[0], op[1], op[2], _none);
case 4: return _emit(instId, op[0], op[1], op[2], op[3]);
case 5: return _emit(instId, op[0], op[1], op[2], op[3], op[4], _none);
case 6: return _emit(instId, op[0], op[1], op[2], op[3], op[4], op[5]);
default:
return DebugUtils::errored(kErrorInvalidArgument);
}
}
// ============================================================================
// [asmjit::CodeEmitter - Finalize]
// ============================================================================
Label CodeEmitter::getLabelByName(const char* name, size_t nameLength, uint32_t parentId) noexcept {
return Label(_code ? _code->getLabelIdByName(name, nameLength, parentId) : static_cast<uint32_t>(0));
}
// ============================================================================
// [asmjit::CodeEmitter - Finalize]
// ============================================================================
Error CodeEmitter::finalize() {
// Finalization does nothing by default, overridden by `CodeBuilder`.
return kErrorOk;
}
// ============================================================================
// [asmjit::CodeEmitter - Error Handling]
// ============================================================================
Error CodeEmitter::setLastError(Error error, const char* message) {
// This is fatal, CodeEmitter can't set error without being attached to `CodeHolder`.
ASMJIT_ASSERT(_code != nullptr);
// Special case used to reset the last error.
if (error == kErrorOk) {
_lastError = kErrorOk;
_globalOptions &= ~kOptionMaybeFailureCase;
return kErrorOk;
}
if (!message)
message = DebugUtils::errorAsString(error);
// Logging is skipped if the error is handled by `ErrorHandler`.
ErrorHandler* handler = _code->_errorHandler;
if (handler && handler->handleError(error, message, this))
return error;
// The handler->handleError() function may throw an exception or longjmp()
// to terminate the execution of `setLastError()`. This is the reason why
// we have delayed changing the `_error` member until now.
_lastError = error;
_globalOptions |= kOptionMaybeFailureCase;
return error;
}
// ============================================================================
// [asmjit::CodeEmitter - Helpers]
// ============================================================================
bool CodeEmitter::isLabelValid(uint32_t id) const noexcept {
size_t index = Operand::unpackId(id);
return _code && index < _code->_labels.getLength();
}
Error CodeEmitter::commentf(const char* fmt, ...) {
Error err = _lastError;
if (err) return err;
#if !defined(ASMJIT_DISABLE_LOGGING)
if (_globalOptions & kOptionLoggingEnabled) {
va_list ap;
va_start(ap, fmt);
err = _code->_logger->logv(fmt, ap);
va_end(ap);
}
#else
ASMJIT_UNUSED(fmt);
#endif
return err;
}
Error CodeEmitter::commentv(const char* fmt, va_list ap) {
Error err = _lastError;
if (err) return err;
#if !defined(ASMJIT_DISABLE_LOGGING)
if (_globalOptions & kOptionLoggingEnabled)
err = _code->_logger->logv(fmt, ap);
#else
ASMJIT_UNUSED(fmt);
ASMJIT_UNUSED(ap);
#endif
return err;
}
// ============================================================================
// [asmjit::CodeEmitter - Emit]
// ============================================================================
#define OP const Operand_&
Error CodeEmitter::emit(uint32_t instId) { return _emit(instId, _none, _none, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0) { return _emit(instId, o0, _none, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1) { return _emit(instId, o0, o1, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2) { return _emit(instId, o0, o1, o2, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3) { return _emit(instId, o0, o1, o2, o3); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4) { return _emit(instId, o0, o1, o2, o3, o4, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, OP o5) { return _emit(instId, o0, o1, o2, o3, o4, o5); }
Error CodeEmitter::emit(uint32_t instId, int o0) { return _emit(instId, Imm(o0), _none, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, int o1) { return _emit(instId, o0, Imm(o1), _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int o2) { return _emit(instId, o0, o1, Imm(o2), _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int o3) { return _emit(instId, o0, o1, o2, Imm(o3)); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); }
Error CodeEmitter::emit(uint32_t instId, int64_t o0) { return _emit(instId, Imm(o0), _none, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, int64_t o1) { return _emit(instId, o0, Imm(o1), _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int64_t o2) { return _emit(instId, o0, o1, Imm(o2), _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int64_t o3) { return _emit(instId, o0, o1, o2, Imm(o3)); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int64_t o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int64_t o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); }
#undef OP
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"

View File

@ -1,499 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CODEEMITTER_H
#define _ASMJIT_BASE_CODEEMITTER_H
// [Dependencies]
#include "../base/arch.h"
#include "../base/codeholder.h"
#include "../base/operand.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [Forward Declarations]
// ============================================================================
class ConstPool;
// ============================================================================
// [asmjit::CodeEmitter]
// ============================================================================
//! Provides a base foundation to emit code - specialized by \ref Assembler and
//! \ref CodeBuilder.
class ASMJIT_VIRTAPI CodeEmitter {
public:
//! CodeEmitter type.
ASMJIT_ENUM(Type) {
kTypeNone = 0,
kTypeAssembler = 1,
kTypeBuilder = 2,
kTypeCompiler = 3,
kTypeCount = 4
};
//! CodeEmitter hints - global settings that affect machine-code generation.
ASMJIT_ENUM(Hints) {
//! Emit optimized code-alignment sequences.
//!
//! Default `true`.
//!
//! X86/X64 Specific
//! ----------------
//!
//! Default align sequence used by X86/X64 architecture is one-byte (0x90)
//! opcode that is often shown by disassemblers as nop. However there are
//! more optimized align sequences for 2-11 bytes that may execute faster.
//! If this feature is enabled AsmJit will generate specialized sequences
//! for alignment between 2 to 11 bytes.
kHintOptimizedAlign = 0x00000001U,
//! Emit jump-prediction hints.
//!
//! Default `false`.
//!
//! X86/X64 Specific
//! ----------------
//!
//! Jump prediction is usually based on the direction of the jump. If the
//! jump is backward it is usually predicted as taken; and if the jump is
//! forward it is usually predicted as not-taken. The reason is that loops
//! generally use backward jumps and conditions usually use forward jumps.
//! However this behavior can be overridden by using instruction prefixes.
//! If this option is enabled these hints will be emitted.
//!
//! This feature is disabled by default, because the only processor that
//! used to take into consideration prediction hints was P4. Newer processors
//! implement heuristics for branch prediction that ignores any static hints.
kHintPredictedJumps = 0x00000002U
};
//! CodeEmitter options that are merged with instruction options.
ASMJIT_ENUM(Options) {
//! Reserved, used to check for errors in `Assembler::_emit()`. In addition,
//! if an emitter is in error state it will have `kOptionMaybeFailureCase`
//! set
kOptionMaybeFailureCase = 0x00000001U,
//! Perform a strict validation before the instruction is emitted.
kOptionStrictValidation = 0x00000002U,
//! Logging is enabled and `CodeHolder::getLogger()` should return a valid
//! \ref Logger pointer.
kOptionLoggingEnabled = 0x00000004U,
//! Mask of all internal options that are not used to represent instruction
//! options, but are used to instrument Assembler and CodeBuilder. These
//! options are internal and should not be used outside of AsmJit itself.
//!
//! NOTE: Reserved options should never appear in `CBInst` options.
kOptionReservedMask = 0x00000007U,
//! Used only by Assembler to mark `_op4` and `_op5` are used.
kOptionOp4Op5Used = 0x00000008U,
//! Prevents following a jump during compilation (CodeCompiler).
kOptionUnfollow = 0x00000010U,
//! Overwrite the destination operand (CodeCompiler).
//!
//! Hint that is important for register liveness analysis. It tells the
//! compiler that the destination operand will be overwritten now or by
//! adjacent instructions. CodeCompiler knows when a register is completely
//! overwritten by a single instruction, for example you don't have to
//! mark "movaps" or "pxor x, x", however, if a pair of instructions is
//! used and the first of them doesn't completely overwrite the content
//! of the destination, CodeCompiler fails to mark that register as dead.
//!
//! X86/X64 Specific
//! ----------------
//!
//! - All instructions that always overwrite at least the size of the
//! register the virtual-register uses , for example "mov", "movq",
//! "movaps" don't need the overwrite option to be used - conversion,
//! shuffle, and other miscellaneous instructions included.
//!
//! - All instructions that clear the destination register if all operands
//! are the same, for example "xor x, x", "pcmpeqb x x", etc...
//!
//! - Consecutive instructions that partially overwrite the variable until
//! there is no old content require the `overwrite()` to be used. Some
//! examples (not always the best use cases thought):
//!
//! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa
//! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa
//! - `mov al, ?` followed by `and ax, 0xFF`
//! - `mov al, ?` followed by `mov ah, al`
//! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1`
//!
//! - If allocated variable is used temporarily for scalar operations. For
//! example if you allocate a full vector like `X86Compiler::newXmm()`
//! and then use that vector for scalar operations you should use
//! `overwrite()` directive:
//!
//! - `sqrtss x, y` - only LO element of `x` is changed, if you don't use
//! HI elements, use `X86Compiler.overwrite().sqrtss(x, y)`.
kOptionOverwrite = 0x00000020U
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_API CodeEmitter(uint32_t type) noexcept;
ASMJIT_API virtual ~CodeEmitter() noexcept;
// --------------------------------------------------------------------------
// [Events]
// --------------------------------------------------------------------------
//! Called after the \ref CodeEmitter was attached to the \ref CodeHolder.
virtual Error onAttach(CodeHolder* code) noexcept = 0;
//! Called after the \ref CodeEmitter was detached from the \ref CodeHolder.
virtual Error onDetach(CodeHolder* code) noexcept = 0;
// --------------------------------------------------------------------------
// [Code-Generation]
// --------------------------------------------------------------------------
//! Emit instruction having max 4 operands.
virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) = 0;
//! Emit instruction having max 6 operands.
virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) = 0;
//! Emit instruction having operands stored in array.
virtual Error _emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount);
//! Create a new label.
virtual Label newLabel() = 0;
//! Create a new named label.
virtual Label newNamedLabel(
const char* name,
size_t nameLength = Globals::kInvalidIndex,
uint32_t type = Label::kTypeGlobal,
uint32_t parentId = 0) = 0;
//! Get a label by name.
//!
//! Returns invalid Label in case that the name is invalid or label was not found.
//!
//! NOTE: This function doesn't trigger ErrorHandler in case the name is
//! invalid or no such label exist. You must always check the validity of the
//! \ref Label returned.
ASMJIT_API Label getLabelByName(
const char* name,
size_t nameLength = Globals::kInvalidIndex,
uint32_t parentId = 0) noexcept;
//! Bind the `label` to the current position of the current section.
//!
//! NOTE: Attempt to bind the same label multiple times will return an error.
virtual Error bind(const Label& label) = 0;
//! Align to the `alignment` specified.
//!
//! The sequence that is used to fill the gap between the aligned location
//! and the current location depends on the align `mode`, see \ref AlignMode.
virtual Error align(uint32_t mode, uint32_t alignment) = 0;
//! Embed raw data into the code-buffer.
virtual Error embed(const void* data, uint32_t size) = 0;
//! Embed absolute label address as data (4 or 8 bytes).
virtual Error embedLabel(const Label& label) = 0;
//! Embed a constant pool into the code-buffer in the following steps:
//! 1. Align by using kAlignData to the minimum `pool` alignment.
//! 2. Bind `label` so it's bound to an aligned location.
//! 3. Emit constant pool data.
virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0;
//! Emit a comment string `s` with an optional `len` parameter.
virtual Error comment(const char* s, size_t len = Globals::kInvalidIndex) = 0;
// --------------------------------------------------------------------------
// [Code-Generation Status]
// --------------------------------------------------------------------------
//! Get if the CodeEmitter is initialized (i.e. attached to a \ref CodeHolder).
ASMJIT_INLINE bool isInitialized() const noexcept { return _code != nullptr; }
ASMJIT_API virtual Error finalize();
// --------------------------------------------------------------------------
// [Code Information]
// --------------------------------------------------------------------------
//! Get information about the code, see \ref CodeInfo.
ASMJIT_INLINE const CodeInfo& getCodeInfo() const noexcept { return _codeInfo; }
//! Get \ref CodeHolder this CodeEmitter is attached to.
ASMJIT_INLINE CodeHolder* getCode() const noexcept { return _code; }
//! Get information about the architecture, see \ref ArchInfo.
ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _codeInfo.getArchInfo(); }
//! Get if the target architecture is 32-bit.
ASMJIT_INLINE bool is32Bit() const noexcept { return getArchInfo().is32Bit(); }
//! Get if the target architecture is 64-bit.
ASMJIT_INLINE bool is64Bit() const noexcept { return getArchInfo().is64Bit(); }
//! Get the target architecture type.
ASMJIT_INLINE uint32_t getArchType() const noexcept { return getArchInfo().getType(); }
//! Get the target architecture sub-type.
ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return getArchInfo().getSubType(); }
//! Get the target architecture's GP register size (4 or 8 bytes).
ASMJIT_INLINE uint32_t getGpSize() const noexcept { return getArchInfo().getGpSize(); }
//! Get the number of target GP registers.
ASMJIT_INLINE uint32_t getGpCount() const noexcept { return getArchInfo().getGpCount(); }
// --------------------------------------------------------------------------
// [Code-Emitter Type]
// --------------------------------------------------------------------------
//! Get the type of this CodeEmitter, see \ref Type.
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
ASMJIT_INLINE bool isAssembler() const noexcept { return _type == kTypeAssembler; }
ASMJIT_INLINE bool isCodeBuilder() const noexcept { return _type == kTypeBuilder; }
ASMJIT_INLINE bool isCodeCompiler() const noexcept { return _type == kTypeCompiler; }
// --------------------------------------------------------------------------
// [Global Information]
// --------------------------------------------------------------------------
//! Get global hints.
ASMJIT_INLINE uint32_t getGlobalHints() const noexcept { return _globalHints; }
//! Get global options.
//!
//! Global options are merged with instruction options before the instruction
//! is encoded. These options have some bits reserved that are used for error
//! checking, logging, and strict validation. Other options are globals that
//! affect each instruction, for example if VEX3 is set globally, it will all
//! instructions, even those that don't have such option set.
ASMJIT_INLINE uint32_t getGlobalOptions() const noexcept { return _globalOptions; }
// --------------------------------------------------------------------------
// [Error Handling]
// --------------------------------------------------------------------------
//! Get if the object is in error state.
//!
//! Error state means that it does not consume anything unless the error
//! state is reset by calling `resetLastError()`. Use `getLastError()` to
//! get the last error that put the object into the error state.
ASMJIT_INLINE bool isInErrorState() const noexcept { return _lastError != kErrorOk; }
//! Get the last error code.
ASMJIT_INLINE Error getLastError() const noexcept { return _lastError; }
//! Set the last error code and propagate it through the error handler.
ASMJIT_API Error setLastError(Error error, const char* message = nullptr);
//! Clear the last error code and return `kErrorOk`.
ASMJIT_INLINE Error resetLastError() noexcept { return setLastError(kErrorOk); }
// --------------------------------------------------------------------------
// [Accessors That Affect the Next Instruction]
// --------------------------------------------------------------------------
//! Get options of the next instruction.
ASMJIT_INLINE uint32_t getOptions() const noexcept { return _options; }
//! Set options of the next instruction.
ASMJIT_INLINE void setOptions(uint32_t options) noexcept { _options = options; }
//! Add options of the next instruction.
ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _options |= options; }
//! Reset options of the next instruction.
ASMJIT_INLINE void resetOptions() noexcept { _options = 0; }
//! Get if the extra register operand is valid.
ASMJIT_INLINE bool hasExtraReg() const noexcept { return _extraReg.isValid(); }
//! Get an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE const RegOnly& getExtraReg() const noexcept { return _extraReg; }
//! Set an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE void setExtraReg(const Reg& reg) noexcept { _extraReg.init(reg); }
//! Set an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); }
//! Reset an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE void resetExtraReg() noexcept { _extraReg.reset(); }
//! Get annotation of the next instruction.
ASMJIT_INLINE const char* getInlineComment() const noexcept { return _inlineComment; }
//! Set annotation of the next instruction.
//!
//! NOTE: This string is set back to null by `_emit()`, but until that it has
//! to remain valid as `CodeEmitter` is not required to make a copy of it (and
//! it would be slow to do that for each instruction).
ASMJIT_INLINE void setInlineComment(const char* s) noexcept { _inlineComment = s; }
//! Reset annotation of the next instruction to null.
ASMJIT_INLINE void resetInlineComment() noexcept { _inlineComment = nullptr; }
// --------------------------------------------------------------------------
// [Helpers]
// --------------------------------------------------------------------------
//! Get if the `label` is valid (i.e. registered).
ASMJIT_INLINE bool isLabelValid(const Label& label) const noexcept {
return isLabelValid(label.getId());
}
//! Get if the label `id` is valid (i.e. registered).
ASMJIT_API bool isLabelValid(uint32_t id) const noexcept;
//! Emit a formatted string `fmt`.
ASMJIT_API Error commentf(const char* fmt, ...);
//! Emit a formatted string `fmt` (va_list version).
ASMJIT_API Error commentv(const char* fmt, va_list ap);
// --------------------------------------------------------------------------
// [Emit]
// --------------------------------------------------------------------------
// NOTE: These `emit()` helpers are designed to address a code-bloat generated
// by C++ compilers to call a function having many arguments. Each parameter to
// `_emit()` requires code to pass it, which means that if we default to 4
// operand parameters in `_emit()` and instId the C++ compiler would have to
// generate a virtual function call having 5 parameters, which is quite a lot.
// Since by default asm instructions have 2 to 3 operands it's better to
// introduce helpers that pass those and fill all the remaining with `_none`.
//! Emit an instruction.
ASMJIT_API Error emit(uint32_t instId);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5);
//! Emit an instruction that has a 32-bit signed immediate operand.
ASMJIT_API Error emit(uint32_t instId, int o0);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, int o1);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, int o2);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, int o3);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, int o4);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, int o5);
//! Emit an instruction that has a 64-bit signed immediate operand.
ASMJIT_API Error emit(uint32_t instId, int64_t o0);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, int64_t o1);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, int64_t o2);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, int64_t o3);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, int64_t o4);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, int64_t o5);
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, unsigned int o0) {
return emit(instId, static_cast<int64_t>(o0));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, unsigned int o1) {
return emit(instId, o0, static_cast<int64_t>(o1));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, unsigned int o2) {
return emit(instId, o0, o1, static_cast<int64_t>(o2));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, unsigned int o3) {
return emit(instId, o0, o1, o2, static_cast<int64_t>(o3));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, unsigned int o4) {
return emit(instId, o0, o1, o2, o3, static_cast<int64_t>(o4));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, unsigned int o5) {
return emit(instId, o0, o1, o2, o3, o4, static_cast<int64_t>(o5));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, uint64_t o0) {
return emit(instId, static_cast<int64_t>(o0));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, uint64_t o1) {
return emit(instId, o0, static_cast<int64_t>(o1));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, uint64_t o2) {
return emit(instId, o0, o1, static_cast<int64_t>(o2));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, uint64_t o3) {
return emit(instId, o0, o1, o2, static_cast<int64_t>(o3));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, uint64_t o4) {
return emit(instId, o0, o1, o2, o3, static_cast<int64_t>(o4));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, uint64_t o5) {
return emit(instId, o0, o1, o2, o3, o4, static_cast<int64_t>(o5));
}
ASMJIT_INLINE Error emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
return _emitOpArray(instId, opArray, opCount);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
CodeInfo _codeInfo; //!< Basic information about the code (matches CodeHolder::_codeInfo).
CodeHolder* _code; //!< CodeHolder the CodeEmitter is attached to.
CodeEmitter* _nextEmitter; //!< Linked list of `CodeEmitter`s attached to the same \ref CodeHolder.
uint8_t _type; //!< See CodeEmitter::Type.
uint8_t _destroyed; //!< Set by ~CodeEmitter() before calling `_code->detach()`.
uint8_t _finalized; //!< True if the CodeEmitter is finalized (CodeBuilder & CodeCompiler).
uint8_t _reserved; //!< \internal
Error _lastError; //!< Last error code.
uint32_t _privateData; //!< Internal private data used freely by any CodeEmitter.
uint32_t _globalHints; //!< Global hints, always in sync with CodeHolder.
uint32_t _globalOptions; //!< Global options, combined with `_options` before used by each instruction.
uint32_t _options; //!< Used to pass instruction options (affects the next instruction).
RegOnly _extraReg; //!< Extra register (op-mask {k} on AVX-512) (affects the next instruction).
const char* _inlineComment; //!< Inline comment of the next instruction (affects the next instruction).
Operand_ _none; //!< Used to pass unused operands to `_emit()` instead of passing null.
Reg _nativeGpReg; //!< Native GP register with zero id.
const Reg* _nativeGpArray; //!< Array of native registers indexed from zero.
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CODEEMITTER_H

View File

@ -1,696 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies]
#include "../base/assembler.h"
#include "../base/utils.h"
#include "../base/vmem.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::ErrorHandler]
// ============================================================================
ErrorHandler::ErrorHandler() noexcept {}
ErrorHandler::~ErrorHandler() noexcept {}
// ============================================================================
// [asmjit::CodeHolder - Utilities]
// ============================================================================
static void CodeHolder_setGlobalOption(CodeHolder* self, uint32_t clear, uint32_t add) noexcept {
// Modify global options of `CodeHolder` itself.
self->_globalOptions = (self->_globalOptions & ~clear) | add;
// Modify all global options of all `CodeEmitter`s attached.
CodeEmitter* emitter = self->_emitters;
while (emitter) {
emitter->_globalOptions = (emitter->_globalOptions & ~clear) | add;
emitter = emitter->_nextEmitter;
}
}
static void CodeHolder_resetInternal(CodeHolder* self, bool releaseMemory) noexcept {
// Detach all `CodeEmitter`s.
while (self->_emitters)
self->detach(self->_emitters);
// Reset everything into its construction state.
self->_codeInfo.reset();
self->_globalHints = 0;
self->_globalOptions = 0;
self->_logger = nullptr;
self->_errorHandler = nullptr;
self->_unresolvedLabelsCount = 0;
self->_trampolinesSize = 0;
// Reset all sections.
size_t numSections = self->_sections.getLength();
for (size_t i = 0; i < numSections; i++) {
SectionEntry* section = self->_sections[i];
if (section->_buffer.hasData() && !section->_buffer.isExternal())
Internal::releaseMemory(section->_buffer._data);
section->_buffer._data = nullptr;
section->_buffer._capacity = 0;
}
// Reset zone allocator and all containers using it.
ZoneHeap* heap = &self->_baseHeap;
self->_namedLabels.reset(heap);
self->_relocations.reset();
self->_labels.reset();
self->_sections.reset();
heap->reset(&self->_baseZone);
self->_baseZone.reset(releaseMemory);
}
// ============================================================================
// [asmjit::CodeHolder - Construction / Destruction]
// ============================================================================
CodeHolder::CodeHolder() noexcept
: _codeInfo(),
_globalHints(0),
_globalOptions(0),
_emitters(nullptr),
_cgAsm(nullptr),
_logger(nullptr),
_errorHandler(nullptr),
_unresolvedLabelsCount(0),
_trampolinesSize(0),
_baseZone(16384 - Zone::kZoneOverhead),
_dataZone(16384 - Zone::kZoneOverhead),
_baseHeap(&_baseZone),
_namedLabels(&_baseHeap) {}
CodeHolder::~CodeHolder() noexcept {
CodeHolder_resetInternal(this, true);
}
// ============================================================================
// [asmjit::CodeHolder - Init / Reset]
// ============================================================================
Error CodeHolder::init(const CodeInfo& info) noexcept {
// Cannot reinitialize if it's locked or there is one or more CodeEmitter
// attached.
if (isInitialized())
return DebugUtils::errored(kErrorAlreadyInitialized);
// If we are just initializing there should be no emitters attached).
ASMJIT_ASSERT(_emitters == nullptr);
// Create the default section and insert it to the `_sections` array.
Error err = _sections.willGrow(&_baseHeap);
if (err == kErrorOk) {
SectionEntry* se = _baseZone.allocZeroedT<SectionEntry>();
if (ASMJIT_LIKELY(se)) {
se->_flags = SectionEntry::kFlagExec | SectionEntry::kFlagConst;
se->_setDefaultName('.', 't', 'e', 'x', 't');
_sections.appendUnsafe(se);
}
else {
err = DebugUtils::errored(kErrorNoHeapMemory);
}
}
if (ASMJIT_UNLIKELY(err)) {
_baseZone.reset(false);
return err;
}
else {
_codeInfo = info;
return kErrorOk;
}
}
void CodeHolder::reset(bool releaseMemory) noexcept {
CodeHolder_resetInternal(this, releaseMemory);
}
// ============================================================================
// [asmjit::CodeHolder - Attach / Detach]
// ============================================================================
Error CodeHolder::attach(CodeEmitter* emitter) noexcept {
// Catch a possible misuse of the API.
if (!emitter)
return DebugUtils::errored(kErrorInvalidArgument);
uint32_t type = emitter->getType();
if (type == CodeEmitter::kTypeNone || type >= CodeEmitter::kTypeCount)
return DebugUtils::errored(kErrorInvalidState);
// This is suspicious, but don't fail if `emitter` matches.
if (emitter->_code != nullptr) {
if (emitter->_code == this) return kErrorOk;
return DebugUtils::errored(kErrorInvalidState);
}
// Special case - attach `Assembler`.
CodeEmitter** pSlot = nullptr;
if (type == CodeEmitter::kTypeAssembler) {
if (_cgAsm)
return DebugUtils::errored(kErrorSlotOccupied);
pSlot = reinterpret_cast<CodeEmitter**>(&_cgAsm);
}
Error err = emitter->onAttach(this);
if (err != kErrorOk) return err;
// Add to a single-linked list of `CodeEmitter`s.
emitter->_nextEmitter = _emitters;
_emitters = emitter;
if (pSlot) *pSlot = emitter;
// Establish the connection.
emitter->_code = this;
return kErrorOk;
}
Error CodeHolder::detach(CodeEmitter* emitter) noexcept {
if (!emitter)
return DebugUtils::errored(kErrorInvalidArgument);
if (emitter->_code != this)
return DebugUtils::errored(kErrorInvalidState);
uint32_t type = emitter->getType();
Error err = kErrorOk;
// NOTE: We always detach if we were asked to, if error happens during
// `emitter->onDetach()` we just propagate it, but the CodeEmitter will
// be detached.
if (!emitter->_destroyed) {
if (type == CodeEmitter::kTypeAssembler)
static_cast<Assembler*>(emitter)->sync();
err = emitter->onDetach(this);
}
// Special case - detach `Assembler`.
if (type == CodeEmitter::kTypeAssembler)
_cgAsm = nullptr;
// Remove from a single-linked list of `CodeEmitter`s.
CodeEmitter** pPrev = &_emitters;
for (;;) {
ASMJIT_ASSERT(*pPrev != nullptr);
CodeEmitter* cur = *pPrev;
if (cur == emitter) {
*pPrev = emitter->_nextEmitter;
break;
}
pPrev = &cur->_nextEmitter;
}
emitter->_code = nullptr;
emitter->_nextEmitter = nullptr;
return err;
}
// ============================================================================
// [asmjit::CodeHolder - Sync]
// ============================================================================
void CodeHolder::sync() noexcept {
if (_cgAsm) _cgAsm->sync();
}
// ============================================================================
// [asmjit::CodeHolder - Result Information]
// ============================================================================
size_t CodeHolder::getCodeSize() const noexcept {
// Reflect all changes first.
const_cast<CodeHolder*>(this)->sync();
// TODO: Support sections.
return _sections[0]->_buffer._length + getTrampolinesSize();
}
// ============================================================================
// [asmjit::CodeHolder - Logging & Error Handling]
// ============================================================================
#if !defined(ASMJIT_DISABLE_LOGGING)
void CodeHolder::setLogger(Logger* logger) noexcept {
uint32_t opt = 0;
if (logger) opt = CodeEmitter::kOptionLoggingEnabled;
_logger = logger;
CodeHolder_setGlobalOption(this, CodeEmitter::kOptionLoggingEnabled, opt);
}
#endif // !ASMJIT_DISABLE_LOGGING
Error CodeHolder::setErrorHandler(ErrorHandler* handler) noexcept {
_errorHandler = handler;
return kErrorOk;
}
// ============================================================================
// [asmjit::CodeHolder - Sections]
// ============================================================================
static Error CodeHolder_reserveInternal(CodeHolder* self, CodeBuffer* cb, size_t n) noexcept {
uint8_t* oldData = cb->_data;
uint8_t* newData;
if (oldData && !cb->isExternal())
newData = static_cast<uint8_t*>(Internal::reallocMemory(oldData, n));
else
newData = static_cast<uint8_t*>(Internal::allocMemory(n));
if (ASMJIT_UNLIKELY(!newData))
return DebugUtils::errored(kErrorNoHeapMemory);
cb->_data = newData;
cb->_capacity = n;
// Update the `Assembler` pointers if attached. Maybe we should introduce an
// event for this, but since only one Assembler can be attached at a time it
// should not matter how these pointers are updated.
Assembler* a = self->_cgAsm;
if (a && &a->_section->_buffer == cb) {
size_t offset = a->getOffset();
a->_bufferData = newData;
a->_bufferEnd = newData + n;
a->_bufferPtr = newData + offset;
}
return kErrorOk;
}
Error CodeHolder::growBuffer(CodeBuffer* cb, size_t n) noexcept {
// This is most likely called by `Assembler` so `sync()` shouldn't be needed,
// however, if this is called by the user and the currently attached Assembler
// did generate some code we could lose that, so sync now and make sure the
// section length is updated.
if (_cgAsm) _cgAsm->sync();
// Now the length of the section must be valid.
size_t length = cb->getLength();
if (ASMJIT_UNLIKELY(n > IntTraits<uintptr_t>::maxValue() - length))
return DebugUtils::errored(kErrorNoHeapMemory);
// We can now check if growing the buffer is really necessary. It's unlikely
// that this function is called while there is still room for `n` bytes.
size_t capacity = cb->getCapacity();
size_t required = cb->getLength() + n;
if (ASMJIT_UNLIKELY(required <= capacity)) return kErrorOk;
if (cb->isFixedSize())
return DebugUtils::errored(kErrorCodeTooLarge);
if (capacity < 8096)
capacity = 8096;
else
capacity += Globals::kAllocOverhead;
do {
size_t old = capacity;
if (capacity < Globals::kAllocThreshold)
capacity *= 2;
else
capacity += Globals::kAllocThreshold;
if (capacity < Globals::kAllocThreshold)
capacity *= 2;
else
capacity += Globals::kAllocThreshold;
// Overflow.
if (ASMJIT_UNLIKELY(old > capacity))
return DebugUtils::errored(kErrorNoHeapMemory);
} while (capacity - Globals::kAllocOverhead < required);
return CodeHolder_reserveInternal(this, cb, capacity - Globals::kAllocOverhead);
}
Error CodeHolder::reserveBuffer(CodeBuffer* cb, size_t n) noexcept {
size_t capacity = cb->getCapacity();
if (n <= capacity) return kErrorOk;
if (cb->isFixedSize())
return DebugUtils::errored(kErrorCodeTooLarge);
// We must sync, as mentioned in `growBuffer()` as well.
if (_cgAsm) _cgAsm->sync();
return CodeHolder_reserveInternal(this, cb, n);
}
// ============================================================================
// [asmjit::CodeHolder - Labels & Symbols]
// ============================================================================
namespace {
//! \internal
//!
//! Only used to lookup a label from `_namedLabels`.
class LabelByName {
public:
ASMJIT_INLINE LabelByName(const char* name, size_t nameLength, uint32_t hVal) noexcept
: name(name),
nameLength(static_cast<uint32_t>(nameLength)) {}
ASMJIT_INLINE bool matches(const LabelEntry* entry) const noexcept {
return static_cast<uint32_t>(entry->getNameLength()) == nameLength &&
::memcmp(entry->getName(), name, nameLength) == 0;
}
const char* name;
uint32_t nameLength;
uint32_t hVal;
};
// Returns a hash of `name` and fixes `nameLength` if it's `Globals::kInvalidIndex`.
static uint32_t CodeHolder_hashNameAndFixLen(const char* name, size_t& nameLength) noexcept {
uint32_t hVal = 0;
if (nameLength == Globals::kInvalidIndex) {
size_t i = 0;
for (;;) {
uint8_t c = static_cast<uint8_t>(name[i]);
if (!c) break;
hVal = Utils::hashRound(hVal, c);
i++;
}
nameLength = i;
}
else {
for (size_t i = 0; i < nameLength; i++) {
uint8_t c = static_cast<uint8_t>(name[i]);
if (ASMJIT_UNLIKELY(!c)) return DebugUtils::errored(kErrorInvalidLabelName);
hVal = Utils::hashRound(hVal, c);
}
}
return hVal;
}
} // anonymous namespace
LabelLink* CodeHolder::newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel) noexcept {
LabelLink* link = _baseHeap.allocT<LabelLink>();
if (ASMJIT_UNLIKELY(!link)) return nullptr;
link->prev = le->_links;
le->_links = link;
link->sectionId = sectionId;
link->relocId = RelocEntry::kInvalidId;
link->offset = offset;
link->rel = rel;
_unresolvedLabelsCount++;
return link;
}
Error CodeHolder::newLabelId(uint32_t& idOut) noexcept {
idOut = 0;
size_t index = _labels.getLength();
if (ASMJIT_LIKELY(index >= Operand::kPackedIdCount))
return DebugUtils::errored(kErrorLabelIndexOverflow);
ASMJIT_PROPAGATE(_labels.willGrow(&_baseHeap));
LabelEntry* le = _baseHeap.allocZeroedT<LabelEntry>();
if (ASMJIT_UNLIKELY(!le))
return DebugUtils::errored(kErrorNoHeapMemory);;
uint32_t id = Operand::packId(static_cast<uint32_t>(index));
le->_setId(id);
le->_parentId = 0;
le->_sectionId = SectionEntry::kInvalidId;
le->_offset = 0;
_labels.appendUnsafe(le);
idOut = id;
return kErrorOk;
}
Error CodeHolder::newNamedLabelId(uint32_t& idOut, const char* name, size_t nameLength, uint32_t type, uint32_t parentId) noexcept {
idOut = 0;
uint32_t hVal = CodeHolder_hashNameAndFixLen(name, nameLength);
if (ASMJIT_UNLIKELY(nameLength == 0))
return DebugUtils::errored(kErrorInvalidLabelName);
if (ASMJIT_UNLIKELY(nameLength > Globals::kMaxLabelLength))
return DebugUtils::errored(kErrorLabelNameTooLong);
switch (type) {
case Label::kTypeLocal:
if (ASMJIT_UNLIKELY(Operand::unpackId(parentId) >= _labels.getLength()))
return DebugUtils::errored(kErrorInvalidParentLabel);
hVal ^= parentId;
break;
case Label::kTypeGlobal:
if (ASMJIT_UNLIKELY(parentId != 0))
return DebugUtils::errored(kErrorNonLocalLabelCantHaveParent);
break;
default:
return DebugUtils::errored(kErrorInvalidArgument);
}
// Don't allow to insert duplicates. Local labels allow duplicates that have
// different id, this is already accomplished by having a different hashes
// between the same label names having different parent labels.
LabelEntry* le = _namedLabels.get(LabelByName(name, nameLength, hVal));
if (ASMJIT_UNLIKELY(le))
return DebugUtils::errored(kErrorLabelAlreadyDefined);
Error err = kErrorOk;
size_t index = _labels.getLength();
if (ASMJIT_UNLIKELY(index >= Operand::kPackedIdCount))
return DebugUtils::errored(kErrorLabelIndexOverflow);
ASMJIT_PROPAGATE(_labels.willGrow(&_baseHeap));
le = _baseHeap.allocZeroedT<LabelEntry>();
if (ASMJIT_UNLIKELY(!le))
return DebugUtils::errored(kErrorNoHeapMemory);
uint32_t id = Operand::packId(static_cast<uint32_t>(index));
le->_hVal = hVal;
le->_setId(id);
le->_type = static_cast<uint8_t>(type);
le->_parentId = 0;
le->_sectionId = SectionEntry::kInvalidId;
le->_offset = 0;
if (le->_name.mustEmbed(nameLength)) {
le->_name.setEmbedded(name, nameLength);
}
else {
char* nameExternal = static_cast<char*>(_dataZone.dup(name, nameLength, true));
if (ASMJIT_UNLIKELY(!nameExternal))
return DebugUtils::errored(kErrorNoHeapMemory);
le->_name.setExternal(nameExternal, nameLength);
}
_labels.appendUnsafe(le);
_namedLabels.put(le);
idOut = id;
return err;
}
uint32_t CodeHolder::getLabelIdByName(const char* name, size_t nameLength, uint32_t parentId) noexcept {
uint32_t hVal = CodeHolder_hashNameAndFixLen(name, nameLength);
if (ASMJIT_UNLIKELY(!nameLength)) return 0;
LabelEntry* le = _namedLabels.get(LabelByName(name, nameLength, hVal));
return le ? le->getId() : static_cast<uint32_t>(0);
}
// ============================================================================
// [asmjit::CodeEmitter - Relocations]
// ============================================================================
//! Encode MOD byte.
static ASMJIT_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcept {
return (m << 6) | (o << 3) | rm;
}
Error CodeHolder::newRelocEntry(RelocEntry** dst, uint32_t type, uint32_t size) noexcept {
ASMJIT_PROPAGATE(_relocations.willGrow(&_baseHeap));
size_t index = _relocations.getLength();
if (ASMJIT_UNLIKELY(index > size_t(0xFFFFFFFFU)))
return DebugUtils::errored(kErrorRelocIndexOverflow);
RelocEntry* re = _baseHeap.allocZeroedT<RelocEntry>();
if (ASMJIT_UNLIKELY(!re))
return DebugUtils::errored(kErrorNoHeapMemory);
re->_id = static_cast<uint32_t>(index);
re->_type = static_cast<uint8_t>(type);
re->_size = static_cast<uint8_t>(size);
re->_sourceSectionId = SectionEntry::kInvalidId;
re->_targetSectionId = SectionEntry::kInvalidId;
_relocations.appendUnsafe(re);
*dst = re;
return kErrorOk;
}
// TODO: Support multiple sections, this only relocates the first.
// TODO: This should go to Runtime as it's responsible for relocating the
// code, CodeHolder should just hold it.
size_t CodeHolder::relocate(void* _dst, uint64_t baseAddress) const noexcept {
SectionEntry* section = _sections[0];
ASMJIT_ASSERT(section != nullptr);
uint8_t* dst = static_cast<uint8_t*>(_dst);
if (baseAddress == Globals::kNoBaseAddress)
baseAddress = static_cast<uint64_t>((uintptr_t)dst);
#if !defined(ASMJIT_DISABLE_LOGGING)
Logger* logger = getLogger();
#endif // ASMJIT_DISABLE_LOGGING
size_t minCodeSize = section->getBuffer().getLength(); // Minimum code size.
size_t maxCodeSize = getCodeSize(); // Includes all possible trampolines.
// We will copy the exact size of the generated code. Extra code for trampolines
// is generated on-the-fly by the relocator (this code doesn't exist at the moment).
::memcpy(dst, section->_buffer._data, minCodeSize);
// Trampoline offset from the beginning of dst/baseAddress.
size_t trampOffset = minCodeSize;
// Relocate all recorded locations.
size_t numRelocs = _relocations.getLength();
const RelocEntry* const* reArray = _relocations.getData();
for (size_t i = 0; i < numRelocs; i++) {
const RelocEntry* re = reArray[i];
// Possibly deleted or optimized out relocation entry.
if (re->getType() == RelocEntry::kTypeNone)
continue;
uint64_t ptr = re->getData();
size_t codeOffset = static_cast<size_t>(re->getSourceOffset());
// Make sure that the `RelocEntry` is correct, we don't want to write
// out of bounds in `dst`.
if (ASMJIT_UNLIKELY(codeOffset + re->getSize() > maxCodeSize))
return DebugUtils::errored(kErrorInvalidRelocEntry);
// Whether to use trampoline, can be only used if relocation type is `kRelocTrampoline`.
bool useTrampoline = false;
switch (re->getType()) {
case RelocEntry::kTypeAbsToAbs: {
break;
}
case RelocEntry::kTypeRelToAbs: {
ptr += baseAddress;
break;
}
case RelocEntry::kTypeAbsToRel: {
ptr -= baseAddress + re->getSourceOffset() + re->getSize();
break;
}
case RelocEntry::kTypeTrampoline: {
if (re->getSize() != 4)
return DebugUtils::errored(kErrorInvalidRelocEntry);
ptr -= baseAddress + re->getSourceOffset() + re->getSize();
if (!Utils::isInt32(static_cast<int64_t>(ptr))) {
ptr = (uint64_t)trampOffset - re->getSourceOffset() - re->getSize();
useTrampoline = true;
}
break;
}
default:
return DebugUtils::errored(kErrorInvalidRelocEntry);
}
switch (re->getSize()) {
case 1:
Utils::writeU8(dst + codeOffset, static_cast<uint32_t>(ptr & 0xFFU));
break;
case 4:
Utils::writeU32u(dst + codeOffset, static_cast<uint32_t>(ptr & 0xFFFFFFFFU));
break;
case 8:
Utils::writeU64u(dst + codeOffset, ptr);
break;
default:
return DebugUtils::errored(kErrorInvalidRelocEntry);
}
// Handle the trampoline case.
if (useTrampoline) {
// Bytes that replace [REX, OPCODE] bytes.
uint32_t byte0 = 0xFF;
uint32_t byte1 = dst[codeOffset - 1];
if (byte1 == 0xE8) {
// Patch CALL/MOD byte to FF/2 (-> 0x15).
byte1 = x86EncodeMod(0, 2, 5);
}
else if (byte1 == 0xE9) {
// Patch JMP/MOD byte to FF/4 (-> 0x25).
byte1 = x86EncodeMod(0, 4, 5);
}
else {
return DebugUtils::errored(kErrorInvalidRelocEntry);
}
// Patch `jmp/call` instruction.
ASMJIT_ASSERT(codeOffset >= 2);
dst[codeOffset - 2] = static_cast<uint8_t>(byte0);
dst[codeOffset - 1] = static_cast<uint8_t>(byte1);
// Store absolute address and advance the trampoline pointer.
Utils::writeU64u(dst + trampOffset, re->getData());
trampOffset += 8;
#if !defined(ASMJIT_DISABLE_LOGGING)
if (logger)
logger->logf("[reloc] dq 0x%016llX ; Trampoline\n", re->getData());
#endif // !ASMJIT_DISABLE_LOGGING
}
}
// If there are no trampolines this is the same as `minCodeSize`.
return trampOffset;
}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"

View File

@ -1,748 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CODEHOLDER_H
#define _ASMJIT_BASE_CODEHOLDER_H
// [Dependencies]
#include "../base/arch.h"
#include "../base/func.h"
#include "../base/logging.h"
#include "../base/operand.h"
#include "../base/simdtypes.h"
#include "../base/utils.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [Forward Declarations]
// ============================================================================
class Assembler;
class CodeEmitter;
class CodeHolder;
// ============================================================================
// [asmjit::AlignMode]
// ============================================================================
//! Align mode.
ASMJIT_ENUM(AlignMode) {
kAlignCode = 0, //!< Align executable code.
kAlignData = 1, //!< Align non-executable code.
kAlignZero = 2, //!< Align by a sequence of zeros.
kAlignCount //!< Count of alignment modes.
};
// ============================================================================
// [asmjit::ErrorHandler]
// ============================================================================
//! Error handler can be used to override the default behavior of error handling
//! available to all classes that inherit \ref CodeEmitter. See \ref handleError().
class ASMJIT_VIRTAPI ErrorHandler {
public:
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `ErrorHandler` instance.
ASMJIT_API ErrorHandler() noexcept;
//! Destroy the `ErrorHandler` instance.
ASMJIT_API virtual ~ErrorHandler() noexcept;
// --------------------------------------------------------------------------
// [Handle Error]
// --------------------------------------------------------------------------
//! Error handler (abstract).
//!
//! Error handler is called after an error happened and before it's propagated
//! to the caller. There are multiple ways how the error handler can be used:
//!
//! 1. Returning `true` or `false` from `handleError()`. If `true` is returned
//! it means that the error was reported and AsmJit can continue execution.
//! The reported error still be propagated to the caller, but won't put the
//! CodeEmitter into an error state (it won't set last-error). However,
//! returning `false` means that the error cannot be handled - in such case
//! it stores the error, which can be then retrieved by using `getLastError()`.
//! Returning `false` is the default behavior when no error handler is present.
//! To put the assembler into a non-error state again a `resetLastError()` must
//! be called.
//!
//! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely
//! exception-safe, but you can throw exception from your error handler if
//! this way is the preferred way of handling errors in your project. Throwing
//! an exception acts virtually as returning `true` as AsmJit won't be able
//! to store the error because the exception changes execution path.
//!
//! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts
//! `CodeEmitter` to a consistent state before calling the `handleError()`
//! so `longjmp()` can be used without any issues to cancel the code
//! generation if an error occurred. There is no difference between
//! exceptions and longjmp() from AsmJit's perspective.
virtual bool handleError(Error err, const char* message, CodeEmitter* origin) = 0;
};
// ============================================================================
// [asmjit::CodeInfo]
// ============================================================================
//! Basic information about a code (or target). It describes its architecture,
//! code generation mode (or optimization level), and base address.
class CodeInfo {
public:
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE CodeInfo() noexcept
: _archInfo(),
_stackAlignment(0),
_cdeclCallConv(CallConv::kIdNone),
_stdCallConv(CallConv::kIdNone),
_fastCallConv(CallConv::kIdNone),
_baseAddress(Globals::kNoBaseAddress) {}
ASMJIT_INLINE CodeInfo(const CodeInfo& other) noexcept { init(other); }
explicit ASMJIT_INLINE CodeInfo(uint32_t archType, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept
: _archInfo(archType, archMode),
_packedMiscInfo(0),
_baseAddress(baseAddress) {}
// --------------------------------------------------------------------------
// [Init / Reset]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isInitialized() const noexcept {
return _archInfo._type != ArchInfo::kTypeNone;
}
ASMJIT_INLINE void init(const CodeInfo& other) noexcept {
_archInfo = other._archInfo;
_packedMiscInfo = other._packedMiscInfo;
_baseAddress = other._baseAddress;
}
ASMJIT_INLINE void init(uint32_t archType, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept {
_archInfo.init(archType, archMode);
_packedMiscInfo = 0;
_baseAddress = baseAddress;
}
ASMJIT_INLINE void reset() noexcept {
_archInfo.reset();
_stackAlignment = 0;
_cdeclCallConv = CallConv::kIdNone;
_stdCallConv = CallConv::kIdNone;
_fastCallConv = CallConv::kIdNone;
_baseAddress = Globals::kNoBaseAddress;
}
// --------------------------------------------------------------------------
// [Architecture Information]
// --------------------------------------------------------------------------
//! Get architecture information, see \ref ArchInfo.
ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _archInfo; }
//! Get architecture type, see \ref ArchInfo::Type.
ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archInfo.getType(); }
//! Get architecture sub-type, see \ref ArchInfo::SubType.
ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return _archInfo.getSubType(); }
//! Get a size of a GP register of the architecture the code is using.
ASMJIT_INLINE uint32_t getGpSize() const noexcept { return _archInfo.getGpSize(); }
//! Get number of GP registers available of the architecture the code is using.
ASMJIT_INLINE uint32_t getGpCount() const noexcept { return _archInfo.getGpCount(); }
// --------------------------------------------------------------------------
// [High-Level Information]
// --------------------------------------------------------------------------
//! Get a natural stack alignment that must be honored (or 0 if not known).
ASMJIT_INLINE uint32_t getStackAlignment() const noexcept { return _stackAlignment; }
//! Set a natural stack alignment that must be honored.
ASMJIT_INLINE void setStackAlignment(uint8_t sa) noexcept { _stackAlignment = static_cast<uint8_t>(sa); }
ASMJIT_INLINE uint32_t getCdeclCallConv() const noexcept { return _cdeclCallConv; }
ASMJIT_INLINE void setCdeclCallConv(uint32_t cc) noexcept { _cdeclCallConv = static_cast<uint8_t>(cc); }
ASMJIT_INLINE uint32_t getStdCallConv() const noexcept { return _stdCallConv; }
ASMJIT_INLINE void setStdCallConv(uint32_t cc) noexcept { _stdCallConv = static_cast<uint8_t>(cc); }
ASMJIT_INLINE uint32_t getFastCallConv() const noexcept { return _fastCallConv; }
ASMJIT_INLINE void setFastCallConv(uint32_t cc) noexcept { _fastCallConv = static_cast<uint8_t>(cc); }
// --------------------------------------------------------------------------
// [Addressing Information]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; }
ASMJIT_INLINE uint64_t getBaseAddress() const noexcept { return _baseAddress; }
ASMJIT_INLINE void setBaseAddress(uint64_t p) noexcept { _baseAddress = p; }
ASMJIT_INLINE void resetBaseAddress() noexcept { _baseAddress = Globals::kNoBaseAddress; }
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
ASMJIT_INLINE CodeInfo& operator=(const CodeInfo& other) noexcept { init(other); return *this; }
ASMJIT_INLINE bool operator==(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) == 0; }
ASMJIT_INLINE bool operator!=(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) != 0; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
ArchInfo _archInfo; //!< Architecture information.
union {
struct {
uint8_t _stackAlignment; //!< Natural stack alignment (ARCH+OS).
uint8_t _cdeclCallConv; //!< Default CDECL calling convention.
uint8_t _stdCallConv; //!< Default STDCALL calling convention.
uint8_t _fastCallConv; //!< Default FASTCALL calling convention.
};
uint32_t _packedMiscInfo; //!< \internal
};
uint64_t _baseAddress; //!< Base address.
};
// ============================================================================
// [asmjit::CodeBuffer]
// ============================================================================
//! Code or data buffer.
struct CodeBuffer {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool hasData() const noexcept { return _data != nullptr; }
ASMJIT_INLINE uint8_t* getData() noexcept { return _data; }
ASMJIT_INLINE const uint8_t* getData() const noexcept { return _data; }
ASMJIT_INLINE size_t getLength() const noexcept { return _length; }
ASMJIT_INLINE size_t getCapacity() const noexcept { return _capacity; }
ASMJIT_INLINE bool isExternal() const noexcept { return _isExternal; }
ASMJIT_INLINE bool isFixedSize() const noexcept { return _isFixedSize; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint8_t* _data; //!< The content of the buffer (data).
size_t _length; //!< Number of bytes of `data` used.
size_t _capacity; //!< Buffer capacity (in bytes).
bool _isExternal; //!< True if this is external buffer.
bool _isFixedSize; //!< True if this buffer cannot grow.
};
// ============================================================================
// [asmjit::SectionEntry]
// ============================================================================
//! Section entry.
class SectionEntry {
public:
ASMJIT_ENUM(Id) {
kInvalidId = 0xFFFFFFFFU //!< Invalid section id.
};
//! Section flags.
ASMJIT_ENUM(Flags) {
kFlagExec = 0x00000001U, //!< Executable (.text sections).
kFlagConst = 0x00000002U, //!< Read-only (.text and .data sections).
kFlagZero = 0x00000004U, //!< Zero initialized by the loader (BSS).
kFlagInfo = 0x00000008U, //!< Info / comment flag.
kFlagImplicit = 0x80000000U //!< Section created implicitly (can be deleted by the Runtime).
};
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
ASMJIT_INLINE const char* getName() const noexcept { return _name; }
ASMJIT_INLINE void _setDefaultName(
char c0 = 0, char c1 = 0, char c2 = 0, char c3 = 0,
char c4 = 0, char c5 = 0, char c6 = 0, char c7 = 0) noexcept {
_nameAsU32[0] = Utils::pack32_4x8(c0, c1, c2, c3);
_nameAsU32[1] = Utils::pack32_4x8(c4, c5, c6, c7);
}
ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; }
ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; }
ASMJIT_INLINE void addFlags(uint32_t flags) noexcept { _flags |= flags; }
ASMJIT_INLINE void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; }
ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; }
ASMJIT_INLINE void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; }
ASMJIT_INLINE size_t getPhysicalSize() const noexcept { return _buffer.getLength(); }
ASMJIT_INLINE size_t getVirtualSize() const noexcept { return _virtualSize; }
ASMJIT_INLINE void setVirtualSize(uint32_t size) noexcept { _virtualSize = size; }
ASMJIT_INLINE CodeBuffer& getBuffer() noexcept { return _buffer; }
ASMJIT_INLINE const CodeBuffer& getBuffer() const noexcept { return _buffer; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint32_t _id; //!< Section id.
uint32_t _flags; //!< Section flags.
uint32_t _alignment; //!< Section alignment requirements (0 if no requirements).
uint32_t _virtualSize; //!< Virtual size of the section (zero initialized mostly).
union {
char _name[36]; //!< Section name (max 35 characters, PE allows max 8).
uint32_t _nameAsU32[36 / 4]; //!< Section name as `uint32_t[]` (only optimization).
};
CodeBuffer _buffer; //!< Code or data buffer.
};
// ============================================================================
// [asmjit::LabelLink]
// ============================================================================
//! Data structure used to link labels.
struct LabelLink {
LabelLink* prev; //!< Previous link (single-linked list).
uint32_t sectionId; //!< Section id.
uint32_t relocId; //!< Relocation id or RelocEntry::kInvalidId.
size_t offset; //!< Label offset relative to the start of the section.
intptr_t rel; //!< Inlined rel8/rel32.
};
// ============================================================================
// [asmjit::LabelEntry]
// ============================================================================
//! Label entry.
//!
//! Contains the following properties:
//! * Label id - This is the only thing that is set to the `Label` operand.
//! * Label name - Optional, used mostly to create executables and libraries.
//! * Label type - Type of the label, default `Label::kTypeAnonymous`.
//! * Label parent id - Derived from many assemblers that allow to define a
//! local label that falls under a global label. This allows to define
//! many labels of the same name that have different parent (global) label.
//! * Offset - offset of the label bound by `Assembler`.
//! * Links - single-linked list that contains locations of code that has
//! to be patched when the label gets bound. Every use of unbound label
//! adds one link to `_links` list.
//! * HVal - Hash value of label's name and optionally parentId.
//! * HashNext - Hash-table implementation detail.
class LabelEntry : public ZoneHashNode {
public:
// NOTE: Label id is stored in `_customData`, which is provided by ZoneHashNode
// to fill a padding that a C++ compiler targeting 64-bit CPU will add to align
// the structure to 64-bits.
//! Get label id.
ASMJIT_INLINE uint32_t getId() const noexcept { return _customData; }
//! Set label id (internal, used only by \ref CodeHolder).
ASMJIT_INLINE void _setId(uint32_t id) noexcept { _customData = id; }
//! Get label type, see \ref Label::Type.
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
//! Get label flags, returns 0 at the moment.
ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; }
ASMJIT_INLINE bool hasParent() const noexcept { return _parentId != 0; }
//! Get label's parent id.
ASMJIT_INLINE uint32_t getParentId() const noexcept { return _parentId; }
//! Get label's section id where it's bound to (or `SectionEntry::kInvalidId` if it's not bound yet).
ASMJIT_INLINE uint32_t getSectionId() const noexcept { return _sectionId; }
//! Get if the label has name.
ASMJIT_INLINE bool hasName() const noexcept { return !_name.isEmpty(); }
//! Get the label's name.
//!
//! NOTE: Local labels will return their local name without their parent
//! part, for example ".L1".
ASMJIT_INLINE const char* getName() const noexcept { return _name.getData(); }
//! Get length of label's name.
//!
//! NOTE: Label name is always null terminated, so you can use `strlen()` to
//! get it, however, it's also cached in `LabelEntry`, so if you want to know
//! the length the easiest way is to use `LabelEntry::getNameLength()`.
ASMJIT_INLINE size_t getNameLength() const noexcept { return _name.getLength(); }
//! Get if the label is bound.
ASMJIT_INLINE bool isBound() const noexcept { return _sectionId != SectionEntry::kInvalidId; }
//! Get the label offset (only useful if the label is bound).
ASMJIT_INLINE intptr_t getOffset() const noexcept { return _offset; }
//! Get the hash-value of label's name and its parent label (if any).
//!
//! Label hash is calculated as `HASH(Name) ^ ParentId`. The hash function
//! is implemented in `Utils::hashString()` and `Utils::hashRound()`.
ASMJIT_INLINE uint32_t getHVal() const noexcept { return _hVal; }
// ------------------------------------------------------------------------
// [Members]
// ------------------------------------------------------------------------
// Let's round the size of `LabelEntry` to 64 bytes (as ZoneHeap has 32
// bytes granularity anyway). This gives `_name` the remaining space, which
// is roughly 16 bytes on 64-bit and 28 bytes on 32-bit architectures.
enum { kNameBytes = 64 - (sizeof(ZoneHashNode) + 16 + sizeof(intptr_t) + sizeof(LabelLink*)) };
uint8_t _type; //!< Label type, see Label::Type.
uint8_t _flags; //!< Must be zero.
uint16_t _reserved16; //!< Reserved.
uint32_t _parentId; //!< Label parent id or zero.
uint32_t _sectionId; //!< Section id or `SectionEntry::kInvalidId`.
uint32_t _reserved32; //!< Reserved.
intptr_t _offset; //!< Label offset.
LabelLink* _links; //!< Label links.
SmallString<kNameBytes> _name; //!< Label name.
};
// ============================================================================
// [asmjit::RelocEntry]
// ============================================================================
//! Relocation entry.
struct RelocEntry {
ASMJIT_ENUM(Id) {
kInvalidId = 0xFFFFFFFFU //!< Invalid relocation id.
};
//! Relocation type.
ASMJIT_ENUM(Type) {
kTypeNone = 0, //!< Deleted entry (no relocation).
kTypeAbsToAbs = 1, //!< Relocate absolute to absolute.
kTypeRelToAbs = 2, //!< Relocate relative to absolute.
kTypeAbsToRel = 3, //!< Relocate absolute to relative.
kTypeTrampoline = 4 //!< Relocate absolute to relative or use trampoline.
};
// ------------------------------------------------------------------------
// [Accessors]
// ------------------------------------------------------------------------
ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
ASMJIT_INLINE uint32_t getSize() const noexcept { return _size; }
ASMJIT_INLINE uint32_t getSourceSectionId() const noexcept { return _sourceSectionId; }
ASMJIT_INLINE uint32_t getTargetSectionId() const noexcept { return _targetSectionId; }
ASMJIT_INLINE uint64_t getSourceOffset() const noexcept { return _sourceOffset; }
ASMJIT_INLINE uint64_t getData() const noexcept { return _data; }
// ------------------------------------------------------------------------
// [Members]
// ------------------------------------------------------------------------
uint32_t _id; //!< Relocation id.
uint8_t _type; //!< Type of the relocation.
uint8_t _size; //!< Size of the relocation (1, 2, 4 or 8 bytes).
uint8_t _reserved[2]; //!< Reserved.
uint32_t _sourceSectionId; //!< Source section id.
uint32_t _targetSectionId; //!< Destination section id.
uint64_t _sourceOffset; //!< Source offset (relative to start of the section).
uint64_t _data; //!< Relocation data (target offset, target address, etc).
};
// ============================================================================
// [asmjit::CodeHolder]
// ============================================================================
//! Contains basic information about the target architecture plus its settings,
//! and holds code & data (including sections, labels, and relocation information).
//! CodeHolder can store both binary and intermediate representation of assembly,
//! which can be generated by \ref Assembler and/or \ref CodeBuilder.
//!
//! NOTE: CodeHolder has ability to attach an \ref ErrorHandler, however, this
//! error handler is not triggered by CodeHolder itself, it's only used by the
//! attached code generators.
class CodeHolder {
public:
ASMJIT_NONCOPYABLE(CodeHolder)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create an uninitialized CodeHolder (you must init() it before it can be used).
ASMJIT_API CodeHolder() noexcept;
//! Destroy the CodeHolder.
ASMJIT_API ~CodeHolder() noexcept;
// --------------------------------------------------------------------------
// [Init / Reset]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isInitialized() const noexcept { return _codeInfo.isInitialized(); }
//! Initialize to CodeHolder to hold code described by `codeInfo`.
ASMJIT_API Error init(const CodeInfo& info) noexcept;
//! Detach all code-generators attached and reset the \ref CodeHolder.
ASMJIT_API void reset(bool releaseMemory = false) noexcept;
// --------------------------------------------------------------------------
// [Attach / Detach]
// --------------------------------------------------------------------------
//! Attach a \ref CodeEmitter to this \ref CodeHolder.
ASMJIT_API Error attach(CodeEmitter* emitter) noexcept;
//! Detach a \ref CodeEmitter from this \ref CodeHolder.
ASMJIT_API Error detach(CodeEmitter* emitter) noexcept;
// --------------------------------------------------------------------------
// [Sync]
// --------------------------------------------------------------------------
//! Synchronize all states of all `CodeEmitter`s associated with the CodeHolder.
//! This is required as some code generators don't sync every time they do
//! something - for example \ref Assembler generally syncs when it needs to
//! reallocate the \ref CodeBuffer, but not each time it encodes instruction
//! or directive.
ASMJIT_API void sync() noexcept;
// --------------------------------------------------------------------------
// [Code-Information]
// --------------------------------------------------------------------------
//! Get code/target information, see \ref CodeInfo.
ASMJIT_INLINE const CodeInfo& getCodeInfo() const noexcept { return _codeInfo; }
//! Get architecture information, see \ref ArchInfo.
ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _codeInfo.getArchInfo(); }
//! Get the target's architecture type.
ASMJIT_INLINE uint32_t getArchType() const noexcept { return getArchInfo().getType(); }
//! Get the target's architecture sub-type.
ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return getArchInfo().getSubType(); }
//! Get if a static base-address is set.
ASMJIT_INLINE bool hasBaseAddress() const noexcept { return _codeInfo.hasBaseAddress(); }
//! Get a static base-address (uint64_t).
ASMJIT_INLINE uint64_t getBaseAddress() const noexcept { return _codeInfo.getBaseAddress(); }
// --------------------------------------------------------------------------
// [Global Information]
// --------------------------------------------------------------------------
//! Get global hints, internally propagated to all `CodeEmitter`s attached.
ASMJIT_INLINE uint32_t getGlobalHints() const noexcept { return _globalHints; }
//! Get global options, internally propagated to all `CodeEmitter`s attached.
ASMJIT_INLINE uint32_t getGlobalOptions() const noexcept { return _globalOptions; }
// --------------------------------------------------------------------------
// [Result Information]
// --------------------------------------------------------------------------
//! Get the size code & data of all sections.
ASMJIT_API size_t getCodeSize() const noexcept;
//! Get size of all possible trampolines.
//!
//! Trampolines are needed to successfully generate relative jumps to absolute
//! addresses. This value is only non-zero if jmp of call instructions were
//! used with immediate operand (this means jumping or calling an absolute
//! address directly).
ASMJIT_INLINE size_t getTrampolinesSize() const noexcept { return _trampolinesSize; }
// --------------------------------------------------------------------------
// [Logging & Error Handling]
// --------------------------------------------------------------------------
#if !defined(ASMJIT_DISABLE_LOGGING)
//! Get if a logger attached.
ASMJIT_INLINE bool hasLogger() const noexcept { return _logger != nullptr; }
//! Get the attached logger.
ASMJIT_INLINE Logger* getLogger() const noexcept { return _logger; }
//! Attach a `logger` to CodeHolder and propagate it to all attached `CodeEmitter`s.
ASMJIT_API void setLogger(Logger* logger) noexcept;
//! Reset the logger (does nothing if not attached).
ASMJIT_INLINE void resetLogger() noexcept { setLogger(nullptr); }
#endif // !ASMJIT_DISABLE_LOGGING
//! Get if error-handler is attached.
ASMJIT_INLINE bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; }
//! Get the error-handler.
ASMJIT_INLINE ErrorHandler* getErrorHandler() const noexcept { return _errorHandler; }
//! Set the error handler, will affect all attached `CodeEmitter`s.
ASMJIT_API Error setErrorHandler(ErrorHandler* handler) noexcept;
//! Reset the error handler (does nothing if not attached).
ASMJIT_INLINE void resetErrorHandler() noexcept { setErrorHandler(nullptr); }
// --------------------------------------------------------------------------
// [Sections]
// --------------------------------------------------------------------------
//! Get array of `SectionEntry*` records.
ASMJIT_INLINE const ZoneVector<SectionEntry*>& getSections() const noexcept { return _sections; }
//! Get a section entry of the given index.
ASMJIT_INLINE SectionEntry* getSectionEntry(size_t index) const noexcept { return _sections[index]; }
ASMJIT_API Error growBuffer(CodeBuffer* cb, size_t n) noexcept;
ASMJIT_API Error reserveBuffer(CodeBuffer* cb, size_t n) noexcept;
// --------------------------------------------------------------------------
// [Labels & Symbols]
// --------------------------------------------------------------------------
//! Create a new anonymous label and return its id in `idOut`.
//!
//! Returns `Error`, does not report error to \ref ErrorHandler.
ASMJIT_API Error newLabelId(uint32_t& idOut) noexcept;
//! Create a new named label label-type `type`.
//!
//! Returns `Error`, does not report error to \ref ErrorHandler.
ASMJIT_API Error newNamedLabelId(uint32_t& idOut, const char* name, size_t nameLength, uint32_t type, uint32_t parentId) noexcept;
//! Get a label id by name.
ASMJIT_API uint32_t getLabelIdByName(const char* name, size_t nameLength = Globals::kInvalidIndex, uint32_t parentId = 0) noexcept;
//! Create a new label-link used to store information about yet unbound labels.
//!
//! Returns `null` if the allocation failed.
ASMJIT_API LabelLink* newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel) noexcept;
//! Get array of `LabelEntry*` records.
ASMJIT_INLINE const ZoneVector<LabelEntry*>& getLabelEntries() const noexcept { return _labels; }
//! Get number of labels created.
ASMJIT_INLINE size_t getLabelsCount() const noexcept { return _labels.getLength(); }
//! Get number of label references, which are unresolved at the moment.
ASMJIT_INLINE size_t getUnresolvedLabelsCount() const noexcept { return _unresolvedLabelsCount; }
//! Get if the `label` is valid (i.e. created by `newLabelId()`).
ASMJIT_INLINE bool isLabelValid(const Label& label) const noexcept {
return isLabelValid(label.getId());
}
//! Get if the label having `id` is valid (i.e. created by `newLabelId()`).
ASMJIT_INLINE bool isLabelValid(uint32_t labelId) const noexcept {
size_t index = Operand::unpackId(labelId);
return index < _labels.getLength();
}
//! Get if the `label` is already bound.
//!
//! Returns `false` if the `label` is not valid.
ASMJIT_INLINE bool isLabelBound(const Label& label) const noexcept {
return isLabelBound(label.getId());
}
//! \overload
ASMJIT_INLINE bool isLabelBound(uint32_t id) const noexcept {
size_t index = Operand::unpackId(id);
return index < _labels.getLength() && _labels[index]->isBound();
}
//! Get a `label` offset or -1 if the label is not yet bound.
ASMJIT_INLINE intptr_t getLabelOffset(const Label& label) const noexcept {
return getLabelOffset(label.getId());
}
//! \overload
ASMJIT_INLINE intptr_t getLabelOffset(uint32_t id) const noexcept {
ASMJIT_ASSERT(isLabelValid(id));
return _labels[Operand::unpackId(id)]->getOffset();
}
//! Get information about the given `label`.
ASMJIT_INLINE LabelEntry* getLabelEntry(const Label& label) const noexcept {
return getLabelEntry(label.getId());
}
//! Get information about a label having the given `id`.
ASMJIT_INLINE LabelEntry* getLabelEntry(uint32_t id) const noexcept {
size_t index = static_cast<size_t>(Operand::unpackId(id));
return index < _labels.getLength() ? _labels[index] : static_cast<LabelEntry*>(nullptr);
}
// --------------------------------------------------------------------------
// [Relocations]
// --------------------------------------------------------------------------
//! Create a new relocation entry of type `type` and size `size`.
//!
//! Additional fields can be set after the relocation entry was created.
ASMJIT_API Error newRelocEntry(RelocEntry** dst, uint32_t type, uint32_t size) noexcept;
//! Get if the code contains relocations.
ASMJIT_INLINE bool hasRelocations() const noexcept { return !_relocations.isEmpty(); }
//! Get array of `RelocEntry*` records.
ASMJIT_INLINE const ZoneVector<RelocEntry*>& getRelocEntries() const noexcept { return _relocations; }
ASMJIT_INLINE RelocEntry* getRelocEntry(uint32_t id) const noexcept { return _relocations[id]; }
//! Relocate the code to `baseAddress` and copy it to `dst`.
//!
//! \param dst Contains the location where the relocated code should be
//! copied. The pointer can be address returned by virtual memory allocator
//! or any other address that has sufficient space.
//!
//! \param baseAddress Base address used for relocation. `JitRuntime` always
//! sets the `baseAddress` to be the same as `dst`.
//!
//! \return The number bytes actually used. If the code emitter reserved
//! space for possible trampolines, but didn't use it, the number of bytes
//! used can actually be less than the expected worst case. Virtual memory
//! allocator can shrink the memory it allocated initially.
//!
//! A given buffer will be overwritten, to get the number of bytes required,
//! use `getCodeSize()`.
ASMJIT_API size_t relocate(void* dst, uint64_t baseAddress = Globals::kNoBaseAddress) const noexcept;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
CodeInfo _codeInfo; //!< Basic information about the code (architecture and other info).
uint32_t _globalHints; //!< Global hints, propagated to all `CodeEmitter`s.
uint32_t _globalOptions; //!< Global options, propagated to all `CodeEmitter`s.
CodeEmitter* _emitters; //!< Linked-list of all attached `CodeEmitter`s.
Assembler* _cgAsm; //!< Attached \ref Assembler (only one at a time).
Logger* _logger; //!< Attached \ref Logger, used by all consumers.
ErrorHandler* _errorHandler; //!< Attached \ref ErrorHandler.
uint32_t _unresolvedLabelsCount; //!< Count of label references which were not resolved.
uint32_t _trampolinesSize; //!< Size of all possible trampolines.
Zone _baseZone; //!< Base zone (used to allocate core structures).
Zone _dataZone; //!< Data zone (used to allocate extra data like label names).
ZoneHeap _baseHeap; //!< Zone allocator, used to manage internal containers.
ZoneVector<SectionEntry*> _sections; //!< Section entries.
ZoneVector<LabelEntry*> _labels; //!< Label entries (each label is stored here).
ZoneVector<RelocEntry*> _relocations; //!< Relocation entries.
ZoneHash<LabelEntry> _namedLabels; //!< Label name -> LabelEntry (only named labels).
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CODEHOLDER_H

View File

@ -1,511 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies]
#include "../base/constpool.h"
#include "../base/utils.h"
#include <algorithm>
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// Binary tree code is based on Julienne Walker's "Andersson Binary Trees"
// article and implementation. However, only three operations are implemented -
// get, insert and traverse.
// ============================================================================
// [asmjit::ConstPool::Tree - Ops]
// ============================================================================
//! \internal
//!
//! Remove left horizontal links.
static ASMJIT_INLINE ConstPool::Node* ConstPoolTree_skewNode(ConstPool::Node* node) noexcept {
ConstPool::Node* link = node->_link[0];
uint32_t level = node->_level;
if (level != 0 && link && link->_level == level) {
node->_link[0] = link->_link[1];
link->_link[1] = node;
node = link;
}
return node;
}
//! \internal
//!
//! Remove consecutive horizontal links.
static ASMJIT_INLINE ConstPool::Node* ConstPoolTree_splitNode(ConstPool::Node* node) noexcept {
ConstPool::Node* link = node->_link[1];
uint32_t level = node->_level;
if (level != 0 && link && link->_link[1] && link->_link[1]->_level == level) {
node->_link[1] = link->_link[0];
link->_link[0] = node;
node = link;
node->_level++;
}
return node;
}
ConstPool::Node* ConstPool::Tree::get(const void* data) noexcept {
ConstPool::Node* node = _root;
size_t dataSize = _dataSize;
while (node) {
int c = ::memcmp(node->getData(), data, dataSize);
if (c == 0)
return node;
node = node->_link[c < 0];
}
return nullptr;
}
void ConstPool::Tree::put(ConstPool::Node* newNode) noexcept {
size_t dataSize = _dataSize;
_length++;
if (!_root) {
_root = newNode;
return;
}
ConstPool::Node* node = _root;
ConstPool::Node* stack[kHeightLimit];
unsigned int top = 0;
unsigned int dir;
// Find a spot and save the stack.
for (;;) {
stack[top++] = node;
dir = ::memcmp(node->getData(), newNode->getData(), dataSize) < 0;
ConstPool::Node* link = node->_link[dir];
if (!link) break;
node = link;
}
// Link and rebalance.
node->_link[dir] = newNode;
while (top > 0) {
// Which child?
node = stack[--top];
if (top != 0) {
dir = stack[top - 1]->_link[1] == node;
}
node = ConstPoolTree_skewNode(node);
node = ConstPoolTree_splitNode(node);
// Fix the parent.
if (top != 0)
stack[top - 1]->_link[dir] = node;
else
_root = node;
}
}
// ============================================================================
// [asmjit::ConstPool - Construction / Destruction]
// ============================================================================
ConstPool::ConstPool(Zone* zone) noexcept { reset(zone); }
ConstPool::~ConstPool() noexcept {}
// ============================================================================
// [asmjit::ConstPool - Reset]
// ============================================================================
void ConstPool::reset(Zone* zone) noexcept {
_zone = zone;
size_t dataSize = 1;
for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) {
_tree[i].reset();
_tree[i].setDataSize(dataSize);
_gaps[i] = nullptr;
dataSize <<= 1;
}
_gapPool = nullptr;
_size = 0;
_alignment = 0;
}
// ============================================================================
// [asmjit::ConstPool - Ops]
// ============================================================================
static ASMJIT_INLINE ConstPool::Gap* ConstPool_allocGap(ConstPool* self) noexcept {
ConstPool::Gap* gap = self->_gapPool;
if (!gap) return self->_zone->allocT<ConstPool::Gap>();
self->_gapPool = gap->_next;
return gap;
}
static ASMJIT_INLINE void ConstPool_freeGap(ConstPool* self, ConstPool::Gap* gap) noexcept {
gap->_next = self->_gapPool;
self->_gapPool = gap;
}
static void ConstPool_addGap(ConstPool* self, size_t offset, size_t length) noexcept {
ASMJIT_ASSERT(length > 0);
while (length > 0) {
size_t gapIndex;
size_t gapLength;
gapIndex = ConstPool::kIndex16;
if (length >= 16 && Utils::isAligned<size_t>(offset, 16)) {
gapLength = 16;
}
else if (length >= 8 && Utils::isAligned<size_t>(offset, 8)) {
gapIndex = ConstPool::kIndex8;
gapLength = 8;
}
else if (length >= 4 && Utils::isAligned<size_t>(offset, 4)) {
gapIndex = ConstPool::kIndex4;
gapLength = 4;
}
else if (length >= 2 && Utils::isAligned<size_t>(offset, 2)) {
gapIndex = ConstPool::kIndex2;
gapLength = 2;
}
else {
gapIndex = ConstPool::kIndex1;
gapLength = 1;
}
// We don't have to check for errors here, if this failed nothing really
// happened (just the gap won't be visible) and it will fail again at
// place where checking will cause kErrorNoHeapMemory.
ConstPool::Gap* gap = ConstPool_allocGap(self);
if (!gap) return;
gap->_next = self->_gaps[gapIndex];
self->_gaps[gapIndex] = gap;
gap->_offset = offset;
gap->_length = gapLength;
offset += gapLength;
length -= gapLength;
}
}
Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept {
size_t treeIndex;
if (size == 32)
treeIndex = kIndex32;
else if (size == 16)
treeIndex = kIndex16;
else if (size == 8)
treeIndex = kIndex8;
else if (size == 4)
treeIndex = kIndex4;
else if (size == 2)
treeIndex = kIndex2;
else if (size == 1)
treeIndex = kIndex1;
else
return DebugUtils::errored(kErrorInvalidArgument);
ConstPool::Node* node = _tree[treeIndex].get(data);
if (node) {
dstOffset = node->_offset;
return kErrorOk;
}
// Before incrementing the current offset try if there is a gap that can
// be used for the requested data.
size_t offset = ~static_cast<size_t>(0);
size_t gapIndex = treeIndex;
while (gapIndex != kIndexCount - 1) {
ConstPool::Gap* gap = _gaps[treeIndex];
// Check if there is a gap.
if (gap) {
size_t gapOffset = gap->_offset;
size_t gapLength = gap->_length;
// Destroy the gap for now.
_gaps[treeIndex] = gap->_next;
ConstPool_freeGap(this, gap);
offset = gapOffset;
ASMJIT_ASSERT(Utils::isAligned<size_t>(offset, size));
gapLength -= size;
if (gapLength > 0)
ConstPool_addGap(this, gapOffset, gapLength);
}
gapIndex++;
}
if (offset == ~static_cast<size_t>(0)) {
// Get how many bytes have to be skipped so the address is aligned accordingly
// to the 'size'.
size_t diff = Utils::alignDiff<size_t>(_size, size);
if (diff != 0) {
ConstPool_addGap(this, _size, diff);
_size += diff;
}
offset = _size;
_size += size;
}
// Add the initial node to the right index.
node = ConstPool::Tree::_newNode(_zone, data, size, offset, false);
if (!node) return DebugUtils::errored(kErrorNoHeapMemory);
_tree[treeIndex].put(node);
_alignment = std::max<size_t>(_alignment, size);
dstOffset = offset;
// Now create a bunch of shared constants that are based on the data pattern.
// We stop at size 4, it probably doesn't make sense to split constants down
// to 1 byte.
size_t pCount = 1;
while (size > 4) {
size >>= 1;
pCount <<= 1;
ASMJIT_ASSERT(treeIndex != 0);
treeIndex--;
const uint8_t* pData = static_cast<const uint8_t*>(data);
for (size_t i = 0; i < pCount; i++, pData += size) {
node = _tree[treeIndex].get(pData);
if (node) continue;
node = ConstPool::Tree::_newNode(_zone, pData, size, offset + (i * size), true);
_tree[treeIndex].put(node);
}
}
return kErrorOk;
}
// ============================================================================
// [asmjit::ConstPool - Reset]
// ============================================================================
struct ConstPoolFill {
ASMJIT_INLINE ConstPoolFill(uint8_t* dst, size_t dataSize) noexcept :
_dst(dst),
_dataSize(dataSize) {}
ASMJIT_INLINE void visit(const ConstPool::Node* node) noexcept {
if (!node->_shared)
::memcpy(_dst + node->_offset, node->getData(), _dataSize);
}
uint8_t* _dst;
size_t _dataSize;
};
void ConstPool::fill(void* dst) const noexcept {
// Clears possible gaps, asmjit should never emit garbage to the output.
::memset(dst, 0, _size);
ConstPoolFill filler(static_cast<uint8_t*>(dst), 1);
for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_tree); i++) {
_tree[i].iterate(filler);
filler._dataSize <<= 1;
}
}
// ============================================================================
// [asmjit::ConstPool - Test]
// ============================================================================
#if defined(ASMJIT_TEST)
UNIT(base_constpool) {
Zone zone(32384 - Zone::kZoneOverhead);
ConstPool pool(&zone);
uint32_t i;
uint32_t kCount = 1000000;
INFO("Adding %u constants to the pool.", kCount);
{
size_t prevOffset;
size_t curOffset;
uint64_t c = ASMJIT_UINT64_C(0x0101010101010101);
EXPECT(pool.add(&c, 8, prevOffset) == kErrorOk,
"pool.add() - Returned error");
EXPECT(prevOffset == 0,
"pool.add() - First constant should have zero offset");
for (i = 1; i < kCount; i++) {
c++;
EXPECT(pool.add(&c, 8, curOffset) == kErrorOk,
"pool.add() - Returned error");
EXPECT(prevOffset + 8 == curOffset,
"pool.add() - Returned incorrect curOffset");
EXPECT(pool.getSize() == (i + 1) * 8,
"pool.getSize() - Reported incorrect size");
prevOffset = curOffset;
}
EXPECT(pool.getAlignment() == 8,
"pool.getAlignment() - Expected 8-byte alignment");
}
INFO("Retrieving %u constants from the pool.", kCount);
{
uint64_t c = ASMJIT_UINT64_C(0x0101010101010101);
for (i = 0; i < kCount; i++) {
size_t offset;
EXPECT(pool.add(&c, 8, offset) == kErrorOk,
"pool.add() - Returned error");
EXPECT(offset == i * 8,
"pool.add() - Should have reused constant");
c++;
}
}
INFO("Checking if the constants were split into 4-byte patterns");
{
uint32_t c = 0x01010101;
for (i = 0; i < kCount; i++) {
size_t offset;
EXPECT(pool.add(&c, 4, offset) == kErrorOk,
"pool.add() - Returned error");
EXPECT(offset == i * 8,
"pool.add() - Should reuse existing constant");
c++;
}
}
INFO("Adding 2 byte constant to misalign the current offset");
{
uint16_t c = 0xFFFF;
size_t offset;
EXPECT(pool.add(&c, 2, offset) == kErrorOk,
"pool.add() - Returned error");
EXPECT(offset == kCount * 8,
"pool.add() - Didn't return expected position");
EXPECT(pool.getAlignment() == 8,
"pool.getAlignment() - Expected 8-byte alignment");
}
INFO("Adding 8 byte constant to check if pool gets aligned again");
{
uint64_t c = ASMJIT_UINT64_C(0xFFFFFFFFFFFFFFFF);
size_t offset;
EXPECT(pool.add(&c, 8, offset) == kErrorOk,
"pool.add() - Returned error");
EXPECT(offset == kCount * 8 + 8,
"pool.add() - Didn't return aligned offset");
}
INFO("Adding 2 byte constant to verify the gap is filled");
{
uint16_t c = 0xFFFE;
size_t offset;
EXPECT(pool.add(&c, 2, offset) == kErrorOk,
"pool.add() - Returned error");
EXPECT(offset == kCount * 8 + 2,
"pool.add() - Didn't fill the gap");
EXPECT(pool.getAlignment() == 8,
"pool.getAlignment() - Expected 8-byte alignment");
}
INFO("Checking reset functionality");
{
pool.reset(&zone);
zone.reset();
EXPECT(pool.getSize() == 0,
"pool.getSize() - Expected pool size to be zero");
EXPECT(pool.getAlignment() == 0,
"pool.getSize() - Expected pool alignment to be zero");
}
INFO("Checking pool alignment when combined constants are added");
{
uint8_t bytes[32] = { 0 };
size_t offset;
pool.add(bytes, 1, offset);
EXPECT(pool.getSize() == 1,
"pool.getSize() - Expected pool size to be 1 byte");
EXPECT(pool.getAlignment() == 1,
"pool.getSize() - Expected pool alignment to be 1 byte");
EXPECT(offset == 0,
"pool.getSize() - Expected offset returned to be zero");
pool.add(bytes, 2, offset);
EXPECT(pool.getSize() == 4,
"pool.getSize() - Expected pool size to be 4 bytes");
EXPECT(pool.getAlignment() == 2,
"pool.getSize() - Expected pool alignment to be 2 bytes");
EXPECT(offset == 2,
"pool.getSize() - Expected offset returned to be 2");
pool.add(bytes, 4, offset);
EXPECT(pool.getSize() == 8,
"pool.getSize() - Expected pool size to be 8 bytes");
EXPECT(pool.getAlignment() == 4,
"pool.getSize() - Expected pool alignment to be 4 bytes");
EXPECT(offset == 4,
"pool.getSize() - Expected offset returned to be 4");
pool.add(bytes, 4, offset);
EXPECT(pool.getSize() == 8,
"pool.getSize() - Expected pool size to be 8 bytes");
EXPECT(pool.getAlignment() == 4,
"pool.getSize() - Expected pool alignment to be 4 bytes");
EXPECT(offset == 4,
"pool.getSize() - Expected offset returned to be 8");
pool.add(bytes, 32, offset);
EXPECT(pool.getSize() == 64,
"pool.getSize() - Expected pool size to be 64 bytes");
EXPECT(pool.getAlignment() == 32,
"pool.getSize() - Expected pool alignment to be 32 bytes");
EXPECT(offset == 32,
"pool.getSize() - Expected offset returned to be 32");
}
}
#endif // ASMJIT_TEST
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"

View File

@ -1,257 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CONSTPOOL_H
#define _ASMJIT_BASE_CONSTPOOL_H
// [Dependencies]
#include "../base/zone.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [asmjit::ConstPool]
// ============================================================================
//! Constant pool.
class ConstPool {
public:
ASMJIT_NONCOPYABLE(ConstPool)
enum {
kIndex1 = 0,
kIndex2 = 1,
kIndex4 = 2,
kIndex8 = 3,
kIndex16 = 4,
kIndex32 = 5,
kIndexCount = 6
};
// --------------------------------------------------------------------------
// [Gap]
// --------------------------------------------------------------------------
//! \internal
//!
//! Zone-allocated const-pool gap.
struct Gap {
Gap* _next; //!< Pointer to the next gap
size_t _offset; //!< Offset of the gap.
size_t _length; //!< Remaining bytes of the gap (basically a gap size).
};
// --------------------------------------------------------------------------
// [Node]
// --------------------------------------------------------------------------
//! \internal
//!
//! Zone-allocated const-pool node.
struct Node {
ASMJIT_INLINE void* getData() const noexcept {
return static_cast<void*>(const_cast<ConstPool::Node*>(this) + 1);
}
Node* _link[2]; //!< Left/Right nodes.
uint32_t _level : 31; //!< Horizontal level for balance.
uint32_t _shared : 1; //!< If this constant is shared with another.
uint32_t _offset; //!< Data offset from the beginning of the pool.
};
// --------------------------------------------------------------------------
// [Tree]
// --------------------------------------------------------------------------
//! \internal
//!
//! Zone-allocated const-pool tree.
struct Tree {
enum {
//! Maximum tree height == log2(1 << 64).
kHeightLimit = 64
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE Tree(size_t dataSize = 0) noexcept
: _root(nullptr),
_length(0),
_dataSize(dataSize) {}
ASMJIT_INLINE ~Tree() {}
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
ASMJIT_INLINE void reset() noexcept {
_root = nullptr;
_length = 0;
}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isEmpty() const noexcept { return _length == 0; }
ASMJIT_INLINE size_t getLength() const noexcept { return _length; }
ASMJIT_INLINE void setDataSize(size_t dataSize) noexcept {
ASMJIT_ASSERT(isEmpty());
_dataSize = dataSize;
}
// --------------------------------------------------------------------------
// [Ops]
// --------------------------------------------------------------------------
ASMJIT_API Node* get(const void* data) noexcept;
ASMJIT_API void put(Node* node) noexcept;
// --------------------------------------------------------------------------
// [Iterate]
// --------------------------------------------------------------------------
template<typename Visitor>
ASMJIT_INLINE void iterate(Visitor& visitor) const noexcept {
Node* node = const_cast<Node*>(_root);
if (!node) return;
Node* stack[kHeightLimit];
size_t top = 0;
for (;;) {
Node* left = node->_link[0];
if (left != nullptr) {
ASMJIT_ASSERT(top != kHeightLimit);
stack[top++] = node;
node = left;
continue;
}
Visit:
visitor.visit(node);
node = node->_link[1];
if (node != nullptr)
continue;
if (top == 0)
return;
node = stack[--top];
goto Visit;
}
}
// --------------------------------------------------------------------------
// [Helpers]
// --------------------------------------------------------------------------
static ASMJIT_INLINE Node* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) noexcept {
Node* node = zone->allocT<Node>(sizeof(Node) + size);
if (ASMJIT_UNLIKELY(!node)) return nullptr;
node->_link[0] = nullptr;
node->_link[1] = nullptr;
node->_level = 1;
node->_shared = shared;
node->_offset = static_cast<uint32_t>(offset);
::memcpy(node->getData(), data, size);
return node;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
Node* _root; //!< Root of the tree
size_t _length; //!< Length of the tree (count of nodes).
size_t _dataSize; //!< Size of the data.
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_API ConstPool(Zone* zone) noexcept;
ASMJIT_API ~ConstPool() noexcept;
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
ASMJIT_API void reset(Zone* zone) noexcept;
// --------------------------------------------------------------------------
// [Ops]
// --------------------------------------------------------------------------
//! Get whether the constant-pool is empty.
ASMJIT_INLINE bool isEmpty() const noexcept { return _size == 0; }
//! Get the size of the constant-pool in bytes.
ASMJIT_INLINE size_t getSize() const noexcept { return _size; }
//! Get minimum alignment.
ASMJIT_INLINE size_t getAlignment() const noexcept { return _alignment; }
//! Add a constant to the constant pool.
//!
//! The constant must have known size, which is 1, 2, 4, 8, 16 or 32 bytes.
//! The constant is added to the pool only if it doesn't not exist, otherwise
//! cached value is returned.
//!
//! AsmJit is able to subdivide added constants, so for example if you add
//! 8-byte constant 0x1122334455667788 it will create the following slots:
//!
//! 8-byte: 0x1122334455667788
//! 4-byte: 0x11223344, 0x55667788
//!
//! The reason is that when combining MMX/SSE/AVX code some patterns are used
//! frequently. However, AsmJit is not able to reallocate a constant that has
//! been already added. For example if you try to add 4-byte constant and then
//! 8-byte constant having the same 4-byte pattern as the previous one, two
//! independent slots will be generated by the pool.
ASMJIT_API Error add(const void* data, size_t size, size_t& dstOffset) noexcept;
// --------------------------------------------------------------------------
// [Fill]
// --------------------------------------------------------------------------
//! Fill the destination with the constants from the pool.
ASMJIT_API void fill(void* dst) const noexcept;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
Zone* _zone; //!< Zone allocator.
Tree _tree[kIndexCount]; //!< Tree per size.
Gap* _gaps[kIndexCount]; //!< Gaps per size.
Gap* _gapPool; //!< Gaps pool
size_t _size; //!< Size of the pool (in bytes).
size_t _alignment; //!< Required pool alignment.
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CONSTPOOL_H

View File

@ -1,674 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies]
#include "../base/cpuinfo.h"
#include "../base/utils.h"
#if ASMJIT_OS_POSIX
# include <errno.h>
# include <sys/utsname.h>
# include <unistd.h>
#endif // ASMJIT_OS_POSIX
#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
# if ASMJIT_CC_MSC_GE(14, 0, 0)
# include <intrin.h> // Required by `__cpuid()` and `_xgetbv()`.
# endif // _MSC_VER >= 1400
#endif
#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
# if ASMJIT_OS_LINUX
# include <sys/auxv.h> // Required by `getauxval()`.
# endif
#endif
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::CpuInfo - Detect ARM]
// ============================================================================
// ARM information has to be retrieved by the OS (this is how ARM was designed).
#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
#if ASMJIT_ARCH_ARM32
static ASMJIT_INLINE void armPopulateBaselineA32Features(CpuInfo* cpuInfo) noexcept {
cpuInfo->_archInfo.init(ArchInfo::kTypeA32);
}
#endif // ASMJIT_ARCH_ARM32
#if ASMJIT_ARCH_ARM64
static ASMJIT_INLINE void armPopulateBaselineA64Features(CpuInfo* cpuInfo) noexcept {
cpuInfo->_archInfo.init(ArchInfo::kTypeA64);
// Thumb (including all variations) is supported on A64 (but not accessible from A64).
cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB);
cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB2);
// A64 is based on ARMv8 and newer.
cpuInfo->addFeature(CpuInfo::kArmFeatureV6);
cpuInfo->addFeature(CpuInfo::kArmFeatureV7);
cpuInfo->addFeature(CpuInfo::kArmFeatureV8);
// A64 comes with these features by default.
cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv2);
cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv3);
cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv4);
cpuInfo->addFeature(CpuInfo::kArmFeatureEDSP);
cpuInfo->addFeature(CpuInfo::kArmFeatureASIMD);
cpuInfo->addFeature(CpuInfo::kArmFeatureIDIVA);
cpuInfo->addFeature(CpuInfo::kArmFeatureIDIVT);
}
#endif // ASMJIT_ARCH_ARM64
#if ASMJIT_OS_WINDOWS
//! \internal
//!
//! Detect ARM CPU features on Windows.
//!
//! The detection is based on `IsProcessorFeaturePresent()` API call.
static ASMJIT_INLINE void armDetectCpuInfoOnWindows(CpuInfo* cpuInfo) noexcept {
#if ASMJIT_ARCH_ARM32
armPopulateBaselineA32Features(cpuInfo);
// Windows for ARM requires at least ARMv7 with DSP extensions.
cpuInfo->addFeature(CpuInfo::kArmFeatureV6);
cpuInfo->addFeature(CpuInfo::kArmFeatureV7);
cpuInfo->addFeature(CpuInfo::kArmFeatureEDSP);
// Windows for ARM requires VFPv3.
cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv2);
cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv3);
// Windows for ARM requires and uses THUMB2.
cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB);
cpuInfo->addFeature(CpuInfo::kArmFeatureTHUMB2);
#else
armPopulateBaselineA64Features(cpuInfo);
#endif
// Windows for ARM requires ASIMD.
cpuInfo->addFeature(CpuInfo::kArmFeatureASIMD);
// Detect additional CPU features by calling `IsProcessorFeaturePresent()`.
struct WinPFPMapping {
uint32_t pfpId;
uint32_t featureId;
};
static const WinPFPMapping mapping[] = {
{ PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE , CpuInfo::kArmFeatureVFPv4 },
{ PF_ARM_VFP_32_REGISTERS_AVAILABLE , CpuInfo::kArmFeatureVFP_D32 },
{ PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE, CpuInfo::kArmFeatureIDIVT },
{ PF_ARM_64BIT_LOADSTORE_ATOMIC , CpuInfo::kArmFeatureAtomics64 }
};
for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(mapping); i++)
if (::IsProcessorFeaturePresent(mapping[i].pfpId))
cpuInfo->addFeature(mapping[i].featureId);
}
#endif // ASMJIT_OS_WINDOWS
#if ASMJIT_OS_LINUX
struct LinuxHWCapMapping {
uint32_t hwcapMask;
uint32_t featureId;
};
static void armDetectHWCaps(CpuInfo* cpuInfo, unsigned long type, const LinuxHWCapMapping* mapping, size_t length) noexcept {
unsigned long mask = getauxval(type);
for (size_t i = 0; i < length; i++)
if ((mask & mapping[i].hwcapMask) == mapping[i].hwcapMask)
cpuInfo->addFeature(mapping[i].featureId);
}
//! \internal
//!
//! Detect ARM CPU features on Linux.
//!
//! The detection is based on `getauxval()`.
ASMJIT_FAVOR_SIZE static void armDetectCpuInfoOnLinux(CpuInfo* cpuInfo) noexcept {
#if ASMJIT_ARCH_ARM32
armPopulateBaselineA32Features(cpuInfo);
// `AT_HWCAP` provides ARMv7 (and less) related flags.
static const LinuxHWCapMapping hwCapMapping[] = {
{ /* HWCAP_VFP */ (1 << 6), CpuInfo::kArmFeatureVFPv2 },
{ /* HWCAP_EDSP */ (1 << 7), CpuInfo::kArmFeatureEDSP },
{ /* HWCAP_NEON */ (1 << 12), CpuInfo::kArmFeatureASIMD },
{ /* HWCAP_VFPv3 */ (1 << 13), CpuInfo::kArmFeatureVFPv3 },
{ /* HWCAP_VFPv4 */ (1 << 16), CpuInfo::kArmFeatureVFPv4 },
{ /* HWCAP_IDIVA */ (1 << 17), CpuInfo::kArmFeatureIDIVA },
{ /* HWCAP_IDIVT */ (1 << 18), CpuInfo::kArmFeatureIDIVT },
{ /* HWCAP_VFPD32 */ (1 << 19), CpuInfo::kArmFeatureVFP_D32 }
};
armDetectHWCaps(cpuInfo, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping));
// VFPv3 implies VFPv2.
if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFPv3)) {
cpuInfo->addFeature(CpuInfo::kArmFeatureVFPv2);
}
// VFPv2 implies ARMv6.
if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFPv2)) {
cpuInfo->addFeature(CpuInfo::kArmFeatureV6);
}
// VFPv3 or ASIMD implies ARMv7.
if (cpuInfo->hasFeature(CpuInfo::kArmFeatureVFPv3) ||
cpuInfo->hasFeature(CpuInfo::kArmFeatureASIMD)) {
cpuInfo->addFeature(CpuInfo::kArmFeatureV7);
}
// `AT_HWCAP2` provides ARMv8+ related flags.
static const LinuxHWCapMapping hwCap2Mapping[] = {
{ /* HWCAP2_AES */ (1 << 0), CpuInfo::kArmFeatureAES },
{ /* HWCAP2_PMULL */ (1 << 1), CpuInfo::kArmFeaturePMULL },
{ /* HWCAP2_SHA1 */ (1 << 2), CpuInfo::kArmFeatureSHA1 },
{ /* HWCAP2_SHA2 */ (1 << 3), CpuInfo::kArmFeatureSHA256 },
{ /* HWCAP2_CRC32 */ (1 << 4), CpuInfo::kArmFeatureCRC32 }
};
armDetectHWCaps(cpuInfo, AT_HWCAP2, hwCap2Mapping, ASMJIT_ARRAY_SIZE(hwCap2Mapping));
if (cpuInfo->hasFeature(CpuInfo::kArmFeatureAES ) ||
cpuInfo->hasFeature(CpuInfo::kArmFeatureCRC32 ) ||
cpuInfo->hasFeature(CpuInfo::kArmFeaturePMULL ) ||
cpuInfo->hasFeature(CpuInfo::kArmFeatureSHA1 ) ||
cpuInfo->hasFeature(CpuInfo::kArmFeatureSHA256)) {
cpuInfo->addFeature(CpuInfo::kArmFeatureV8);
}
#else
armPopulateBaselineA64Features(cpuInfo);
// `AT_HWCAP` provides ARMv8+ related flags.
static const LinuxHWCapMapping hwCapMapping[] = {
{ /* HWCAP_ASIMD */ (1 << 1), CpuInfo::kArmFeatureASIMD },
{ /* HWCAP_AES */ (1 << 3), CpuInfo::kArmFeatureAES },
{ /* HWCAP_CRC32 */ (1 << 7), CpuInfo::kArmFeatureCRC32 },
{ /* HWCAP_PMULL */ (1 << 4), CpuInfo::kArmFeaturePMULL },
{ /* HWCAP_SHA1 */ (1 << 5), CpuInfo::kArmFeatureSHA1 },
{ /* HWCAP_SHA2 */ (1 << 6), CpuInfo::kArmFeatureSHA256 },
{ /* HWCAP_ATOMICS */ (1 << 8), CpuInfo::kArmFeatureAtomics64 }
};
armDetectHWCaps(cpuInfo, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping));
// `AT_HWCAP2` is not used at the moment.
#endif
}
#endif // ASMJIT_OS_LINUX
ASMJIT_FAVOR_SIZE static void armDetectCpuInfo(CpuInfo* cpuInfo) noexcept {
#if ASMJIT_OS_WINDOWS
armDetectCpuInfoOnWindows(cpuInfo);
#elif ASMJIT_OS_LINUX
armDetectCpuInfoOnLinux(cpuInfo);
#else
# error "[asmjit] armDetectCpuInfo() - Unsupported OS."
#endif
}
#endif // ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
// ============================================================================
// [asmjit::CpuInfo - Detect X86]
// ============================================================================
#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
//! \internal
//!
//! X86 CPUID result.
struct CpuIdResult {
uint32_t eax, ebx, ecx, edx;
};
//! \internal
//!
//! Content of XCR register, result of XGETBV instruction.
struct XGetBVResult {
uint32_t eax, edx;
};
#if ASMJIT_CC_MSC && !ASMJIT_CC_MSC_GE(15, 0, 30729) && ASMJIT_ARCH_X64
//! \internal
//!
//! HACK: VS2008 or less, 64-bit mode - `__cpuidex` doesn't exist! However,
//! 64-bit calling convention specifies the first parameter to be passed by
//! ECX, so we may be lucky if compiler doesn't move the register, otherwise
//! the result would be wrong.
static void ASMJIT_NOINLINE void x86CallCpuIdWorkaround(uint32_t inEcx, uint32_t inEax, CpuIdResult* result) noexcept {
__cpuid(reinterpret_cast<int*>(result), inEax);
}
#endif
//! \internal
//!
//! Wrapper to call `cpuid` instruction.
static void ASMJIT_INLINE x86CallCpuId(CpuIdResult* result, uint32_t inEax, uint32_t inEcx = 0) noexcept {
#if ASMJIT_CC_MSC && ASMJIT_CC_MSC_GE(15, 0, 30729)
__cpuidex(reinterpret_cast<int*>(result), inEax, inEcx);
#elif ASMJIT_CC_MSC && ASMJIT_ARCH_X64
x86CallCpuIdWorkaround(inEcx, inEax, result);
#elif ASMJIT_CC_MSC && ASMJIT_ARCH_X86
uint32_t paramEax = inEax;
uint32_t paramEcx = inEcx;
uint32_t* out = reinterpret_cast<uint32_t*>(result);
__asm {
mov eax, paramEax
mov ecx, paramEcx
mov edi, out
cpuid
mov dword ptr[edi + 0], eax
mov dword ptr[edi + 4], ebx
mov dword ptr[edi + 8], ecx
mov dword ptr[edi + 12], edx
}
#elif (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && ASMJIT_ARCH_X86
__asm__ __volatile__(
"mov %%ebx, %%edi\n"
"cpuid\n"
"xchg %%edi, %%ebx\n"
: "=a"(result->eax),
"=D"(result->ebx),
"=c"(result->ecx),
"=d"(result->edx)
: "a"(inEax),
"c"(inEcx));
#elif (ASMJIT_CC_GCC || ASMJIT_CC_CLANG || ASMJIT_CC_INTEL) && ASMJIT_ARCH_X64
__asm__ __volatile__(
"mov %%rbx, %%rdi\n"
"cpuid\n"
"xchg %%rdi, %%rbx\n"
: "=a"(result->eax),
"=D"(result->ebx),
"=c"(result->ecx),
"=d"(result->edx)
: "a"(inEax),
"c"(inEcx));
#else
# error "[asmjit] x86CallCpuid() - Unsupported compiler."
#endif
}
//! \internal
//!
//! Wrapper to call `xgetbv` instruction.
static ASMJIT_INLINE void x86CallXGetBV(XGetBVResult* result, uint32_t inEcx) noexcept {
#if ASMJIT_CC_MSC_GE(16, 0, 40219) // 2010SP1+
uint64_t value = _xgetbv(inEcx);
result->eax = static_cast<uint32_t>(value & 0xFFFFFFFFU);
result->edx = static_cast<uint32_t>(value >> 32);
#elif ASMJIT_CC_GCC || ASMJIT_CC_CLANG
uint32_t outEax;
uint32_t outEdx;
// Replaced, because the world is not perfect:
// __asm__ __volatile__("xgetbv" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx));
__asm__ __volatile__(".byte 0x0F, 0x01, 0xd0" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx));
result->eax = outEax;
result->edx = outEdx;
#else
result->eax = 0;
result->edx = 0;
#endif
}
//! \internal
//!
//! Map a 12-byte vendor string returned by `cpuid` into a `CpuInfo::Vendor` ID.
static ASMJIT_INLINE uint32_t x86GetCpuVendorID(const char* vendorString) noexcept {
struct VendorData {
uint32_t id;
char text[12];
};
static const VendorData vendorList[] = {
{ CpuInfo::kVendorIntel , { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l' } },
{ CpuInfo::kVendorAMD , { 'A', 'u', 't', 'h', 'e', 'n', 't', 'i', 'c', 'A', 'M', 'D' } },
{ CpuInfo::kVendorVIA , { 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 } },
{ CpuInfo::kVendorVIA , { 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' } }
};
uint32_t dw0 = reinterpret_cast<const uint32_t*>(vendorString)[0];
uint32_t dw1 = reinterpret_cast<const uint32_t*>(vendorString)[1];
uint32_t dw2 = reinterpret_cast<const uint32_t*>(vendorString)[2];
for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(vendorList); i++) {
if (dw0 == reinterpret_cast<const uint32_t*>(vendorList[i].text)[0] &&
dw1 == reinterpret_cast<const uint32_t*>(vendorList[i].text)[1] &&
dw2 == reinterpret_cast<const uint32_t*>(vendorList[i].text)[2])
return vendorList[i].id;
}
return CpuInfo::kVendorNone;
}
static ASMJIT_INLINE void x86SimplifyBrandString(char* s) noexcept {
// Used to always clear the current character to ensure that the result
// doesn't contain garbage after the new zero terminator.
char* d = s;
char prev = 0;
char curr = s[0];
s[0] = '\0';
for (;;) {
if (curr == 0)
break;
if (curr == ' ') {
if (prev == '@' || s[1] == ' ' || s[1] == '@')
goto L_Skip;
}
d[0] = curr;
d++;
prev = curr;
L_Skip:
curr = *++s;
s[0] = '\0';
}
d[0] = '\0';
}
ASMJIT_FAVOR_SIZE static void x86DetectCpuInfo(CpuInfo* cpuInfo) noexcept {
uint32_t i, maxId;
CpuIdResult regs;
XGetBVResult xcr0 = { 0, 0 };
cpuInfo->_archInfo.init(ArchInfo::kTypeHost);
cpuInfo->addFeature(CpuInfo::kX86FeatureI486);
// --------------------------------------------------------------------------
// [CPUID EAX=0x0]
// --------------------------------------------------------------------------
// Get vendor string/id.
x86CallCpuId(&regs, 0x0);
maxId = regs.eax;
::memcpy(cpuInfo->_vendorString + 0, &regs.ebx, 4);
::memcpy(cpuInfo->_vendorString + 4, &regs.edx, 4);
::memcpy(cpuInfo->_vendorString + 8, &regs.ecx, 4);
cpuInfo->_vendorId = x86GetCpuVendorID(cpuInfo->_vendorString);
// --------------------------------------------------------------------------
// [CPUID EAX=0x1]
// --------------------------------------------------------------------------
if (maxId >= 0x1) {
// Get feature flags in ECX/EDX and family/model in EAX.
x86CallCpuId(&regs, 0x1);
// Fill family and model fields.
cpuInfo->_family = (regs.eax >> 8) & 0x0F;
cpuInfo->_model = (regs.eax >> 4) & 0x0F;
cpuInfo->_stepping = (regs.eax ) & 0x0F;
// Use extended family and model fields.
if (cpuInfo->_family == 0x0F) {
cpuInfo->_family += ((regs.eax >> 20) & 0xFF);
cpuInfo->_model += ((regs.eax >> 16) & 0x0F) << 4;
}
cpuInfo->_x86Data._processorType = ((regs.eax >> 12) & 0x03);
cpuInfo->_x86Data._brandIndex = ((regs.ebx ) & 0xFF);
cpuInfo->_x86Data._flushCacheLineSize = ((regs.ebx >> 8) & 0xFF) * 8;
cpuInfo->_x86Data._maxLogicalProcessors = ((regs.ebx >> 16) & 0xFF);
if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE3);
if (regs.ecx & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeaturePCLMULQDQ);
if (regs.ecx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureMONITOR);
if (regs.ecx & 0x00000200U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSSE3);
if (regs.ecx & 0x00002000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMPXCHG16B);
if (regs.ecx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4_1);
if (regs.ecx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4_2);
if (regs.ecx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMOVBE);
if (regs.ecx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeaturePOPCNT);
if (regs.ecx & 0x02000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAESNI);
if (regs.ecx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVE);
if (regs.ecx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureOSXSAVE);
if (regs.ecx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDRAND);
if (regs.edx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDTSC);
if (regs.edx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureMSR);
if (regs.edx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMPXCHG8B);
if (regs.edx & 0x00008000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCMOV);
if (regs.edx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLFLUSH);
if (regs.edx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMMX);
if (regs.edx & 0x01000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFXSR);
if (regs.edx & 0x02000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE)
.addFeature(CpuInfo::kX86FeatureMMX2);
if (regs.edx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE)
.addFeature(CpuInfo::kX86FeatureSSE2);
if (regs.edx & 0x10000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMT);
// Get the content of XCR0 if supported by CPU and enabled by OS.
if ((regs.ecx & 0x0C000000U) == 0x0C000000U) {
x86CallXGetBV(&xcr0, 0);
}
// Detect AVX+.
if (regs.ecx & 0x10000000U) {
// - XCR0[2:1] == 11b
// XMM & YMM states need to be enabled by OS.
if ((xcr0.eax & 0x00000006U) == 0x00000006U) {
cpuInfo->addFeature(CpuInfo::kX86FeatureAVX);
if (regs.ecx & 0x00001000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFMA);
if (regs.ecx & 0x20000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureF16C);
}
}
}
// --------------------------------------------------------------------------
// [CPUID EAX=0x7]
// --------------------------------------------------------------------------
// Detect new features if the processor supports CPUID-07.
bool maybeMPX = false;
if (maxId >= 0x7) {
x86CallCpuId(&regs, 0x7);
if (regs.ebx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureFSGSBASE);
if (regs.ebx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureBMI);
if (regs.ebx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureHLE);
if (regs.ebx & 0x00000080U) cpuInfo->addFeature(CpuInfo::kX86FeatureSMEP);
if (regs.ebx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeatureBMI2);
if (regs.ebx & 0x00000200U) cpuInfo->addFeature(CpuInfo::kX86FeatureERMS);
if (regs.ebx & 0x00000800U) cpuInfo->addFeature(CpuInfo::kX86FeatureRTM);
if (regs.ebx & 0x00004000U) maybeMPX = true;
if (regs.ebx & 0x00040000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDSEED);
if (regs.ebx & 0x00080000U) cpuInfo->addFeature(CpuInfo::kX86FeatureADX);
if (regs.ebx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSMAP);
if (regs.ebx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeaturePCOMMIT);
if (regs.ebx & 0x00800000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLFLUSHOPT);
if (regs.ebx & 0x01000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLWB);
if (regs.ebx & 0x20000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSHA);
if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeaturePREFETCHWT1);
// TSX is supported if at least one of `HLE` and `RTM` is supported.
if (regs.ebx & 0x00000810U) cpuInfo->addFeature(CpuInfo::kX86FeatureTSX);
// Detect AVX2.
if (cpuInfo->hasFeature(CpuInfo::kX86FeatureAVX)) {
if (regs.ebx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX2);
}
// Detect AVX-512+.
if (regs.ebx & 0x00010000U) {
// - XCR0[2:1] == 11b
// XMM/YMM states need to be enabled by OS.
// - XCR0[7:5] == 111b
// Upper 256-bit of ZMM0-XMM15 and ZMM16-ZMM31 need to be enabled by the OS.
if ((xcr0.eax & 0x000000E6U) == 0x000000E6U) {
cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_F);
if (regs.ebx & 0x00020000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_DQ);
if (regs.ebx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_IFMA);
if (regs.ebx & 0x04000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_PFI);
if (regs.ebx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_ERI);
if (regs.ebx & 0x10000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_CDI);
if (regs.ebx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_BW);
if (regs.ebx & 0x80000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_VL);
if (regs.ecx & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_VBMI);
if (regs.ecx & 0x00004000U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_VPOPCNTDQ);
if (regs.edx & 0x00000004U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_4VNNIW);
if (regs.edx & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX512_4FMAPS);
}
}
}
// --------------------------------------------------------------------------
// [CPUID EAX=0xD]
// --------------------------------------------------------------------------
if (maxId >= 0xD) {
x86CallCpuId(&regs, 0xD, 0);
// Both CPUID result and XCR0 has to be enabled to have support for MPX.
if (((regs.eax & xcr0.eax) & 0x00000018U) == 0x00000018U && maybeMPX)
cpuInfo->addFeature(CpuInfo::kX86FeatureMPX);
x86CallCpuId(&regs, 0xD, 1);
if (regs.eax & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVEOPT);
if (regs.eax & 0x00000002U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVEC);
if (regs.eax & 0x00000008U) cpuInfo->addFeature(CpuInfo::kX86FeatureXSAVES);
}
// --------------------------------------------------------------------------
// [CPUID EAX=0x80000000...maxId]
// --------------------------------------------------------------------------
// The highest EAX that we understand.
uint32_t kHighestProcessedEAX = 0x80000008U;
// Several CPUID calls are required to get the whole branc string. It's easy
// to copy one DWORD at a time instead of performing a byte copy.
uint32_t* brand = reinterpret_cast<uint32_t*>(cpuInfo->_brandString);
i = maxId = 0x80000000U;
do {
x86CallCpuId(&regs, i);
switch (i) {
case 0x80000000U:
maxId = std::min<uint32_t>(regs.eax, kHighestProcessedEAX);
break;
case 0x80000001U:
if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureLAHFSAHF);
if (regs.ecx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureLZCNT);
if (regs.ecx & 0x00000040U) cpuInfo->addFeature(CpuInfo::kX86FeatureSSE4A);
if (regs.ecx & 0x00000080U) cpuInfo->addFeature(CpuInfo::kX86FeatureMSSE);
if (regs.ecx & 0x00000100U) cpuInfo->addFeature(CpuInfo::kX86FeaturePREFETCHW);
if (regs.ecx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureTBM);
if (regs.edx & 0x00100000U) cpuInfo->addFeature(CpuInfo::kX86FeatureNX);
if (regs.edx & 0x00200000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFXSROPT);
if (regs.edx & 0x00400000U) cpuInfo->addFeature(CpuInfo::kX86FeatureMMX2);
if (regs.edx & 0x08000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureRDTSCP);
if (regs.edx & 0x40000000U) cpuInfo->addFeature(CpuInfo::kX86Feature3DNOW2)
.addFeature(CpuInfo::kX86FeatureMMX2);
if (regs.edx & 0x80000000U) cpuInfo->addFeature(CpuInfo::kX86Feature3DNOW);
if (cpuInfo->hasFeature(CpuInfo::kX86FeatureAVX)) {
if (regs.ecx & 0x00000800U) cpuInfo->addFeature(CpuInfo::kX86FeatureXOP);
if (regs.ecx & 0x00010000U) cpuInfo->addFeature(CpuInfo::kX86FeatureFMA4);
}
// These seem to be only supported by AMD.
if (cpuInfo->getVendorId() == CpuInfo::kVendorAMD) {
if (regs.ecx & 0x00000010U) cpuInfo->addFeature(CpuInfo::kX86FeatureALTMOVCR8);
}
break;
case 0x80000002U:
case 0x80000003U:
case 0x80000004U:
*brand++ = regs.eax;
*brand++ = regs.ebx;
*brand++ = regs.ecx;
*brand++ = regs.edx;
// Go directly to the last one.
if (i == 0x80000004U) i = 0x80000008U - 1;
break;
case 0x80000008U:
if (regs.ebx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeatureCLZERO);
break;
}
} while (++i <= maxId);
// Simplify CPU brand string by removing unnecessary spaces.
x86SimplifyBrandString(cpuInfo->_brandString);
}
#endif // ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
// ============================================================================
// [asmjit::CpuInfo - Detect - HWThreadsCount]
// ============================================================================
static ASMJIT_INLINE uint32_t cpuDetectHWThreadsCount() noexcept {
#if ASMJIT_OS_WINDOWS
SYSTEM_INFO info;
::GetSystemInfo(&info);
return info.dwNumberOfProcessors;
#elif ASMJIT_OS_POSIX && defined(_SC_NPROCESSORS_ONLN)
long res = ::sysconf(_SC_NPROCESSORS_ONLN);
if (res <= 0) return 1;
return static_cast<uint32_t>(res);
#else
return 1;
#endif
}
// ============================================================================
// [asmjit::CpuInfo - Detect]
// ============================================================================
ASMJIT_FAVOR_SIZE void CpuInfo::detect() noexcept {
reset();
#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
armDetectCpuInfo(this);
#endif // ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
#if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
x86DetectCpuInfo(this);
#endif // ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
_hwThreadsCount = cpuDetectHWThreadsCount();
}
// ============================================================================
// [asmjit::CpuInfo - GetHost]
// ============================================================================
struct HostCpuInfo : public CpuInfo {
ASMJIT_INLINE HostCpuInfo() noexcept : CpuInfo() { detect(); }
};
const CpuInfo& CpuInfo::getHost() noexcept {
static HostCpuInfo host;
return host;
}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"

View File

@ -1,373 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CPUINFO_H
#define _ASMJIT_BASE_CPUINFO_H
// [Dependencies]
#include "../base/arch.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [asmjit::CpuFeatures]
// ============================================================================
class CpuFeatures {
public:
typedef uintptr_t BitWord;
enum {
kMaxFeatures = 128,
kBitWordSize = static_cast<int>(sizeof(BitWord)) * 8,
kNumBitWords = kMaxFeatures / kBitWordSize
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE CpuFeatures() noexcept { reset(); }
ASMJIT_INLINE CpuFeatures(const CpuFeatures& other) noexcept { init(other); }
// --------------------------------------------------------------------------
// [Init / Reset]
// --------------------------------------------------------------------------
ASMJIT_INLINE void init(const CpuFeatures& other) noexcept { ::memcpy(this, &other, sizeof(*this)); }
ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); }
// --------------------------------------------------------------------------
// [Ops]
// --------------------------------------------------------------------------
//! Get all features as `BitWord` array.
ASMJIT_INLINE BitWord* getBits() noexcept { return _bits; }
//! Get all features as `BitWord` array (const).
ASMJIT_INLINE const BitWord* getBits() const noexcept { return _bits; }
//! Get if feature `feature` is present.
ASMJIT_INLINE bool has(uint32_t feature) const noexcept {
ASMJIT_ASSERT(feature < kMaxFeatures);
uint32_t idx = feature / kBitWordSize;
uint32_t bit = feature % kBitWordSize;
return static_cast<bool>((_bits[idx] >> bit) & 0x1);
}
//! Get if all features as defined by `other` are present.
ASMJIT_INLINE bool hasAll(const CpuFeatures& other) const noexcept {
for (uint32_t i = 0; i < kNumBitWords; i++)
if ((_bits[i] & other._bits[i]) != other._bits[i])
return false;
return true;
}
//! Add a CPU `feature`.
ASMJIT_INLINE CpuFeatures& add(uint32_t feature) noexcept {
ASMJIT_ASSERT(feature < kMaxFeatures);
uint32_t idx = feature / kBitWordSize;
uint32_t bit = feature % kBitWordSize;
_bits[idx] |= static_cast<BitWord>(1) << bit;
return *this;
}
//! Remove a CPU `feature`.
ASMJIT_INLINE CpuFeatures& remove(uint32_t feature) noexcept {
ASMJIT_ASSERT(feature < kMaxFeatures);
uint32_t idx = feature / kBitWordSize;
uint32_t bit = feature % kBitWordSize;
_bits[idx] &= ~(static_cast<BitWord>(1) << bit);
return *this;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
BitWord _bits[kNumBitWords];
};
// ============================================================================
// [asmjit::CpuInfo]
// ============================================================================
//! CPU information.
class CpuInfo {
public:
//! CPU vendor ID.
ASMJIT_ENUM(Vendor) {
kVendorNone = 0, //!< Generic or unknown.
kVendorIntel = 1, //!< Intel vendor.
kVendorAMD = 2, //!< AMD vendor.
kVendorVIA = 3 //!< VIA vendor.
};
//! ARM/ARM64 CPU features.
ASMJIT_ENUM(ArmFeatures) {
kArmFeatureV6 = 1, //!< ARMv6 instruction set.
kArmFeatureV7, //!< ARMv7 instruction set.
kArmFeatureV8, //!< ARMv8 instruction set.
kArmFeatureTHUMB, //!< CPU provides THUMB v1 instruction set (THUMB mode).
kArmFeatureTHUMB2, //!< CPU provides THUMB v2 instruction set (THUMB mode).
kArmFeatureVFPv2, //!< CPU provides VFPv2 instruction set.
kArmFeatureVFPv3, //!< CPU provides VFPv3 instruction set.
kArmFeatureVFPv4, //!< CPU provides VFPv4 instruction set.
kArmFeatureVFP_D32, //!< CPU provides 32 VFP-D (64-bit) registers.
kArmFeatureEDSP, //!< CPU provides EDSP extensions.
kArmFeatureASIMD, //!< CPU provides 'Advanced SIMD'.
kArmFeatureIDIVA, //!< CPU provides hardware SDIV and UDIV (ARM mode).
kArmFeatureIDIVT, //!< CPU provides hardware SDIV and UDIV (THUMB mode).
kArmFeatureAES, //!< CPU provides AES instructions (ARM64 only).
kArmFeatureCRC32, //!< CPU provides CRC32 instructions.
kArmFeaturePMULL, //!< CPU provides PMULL instructions (ARM64 only).
kArmFeatureSHA1, //!< CPU provides SHA1 instructions.
kArmFeatureSHA256, //!< CPU provides SHA256 instructions.
kArmFeatureAtomics64, //!< CPU provides 64-bit load/store atomics (ARM64 only).
kArmFeaturesCount //!< Count of ARM/ARM64 CPU features.
};
//! X86/X64 CPU features.
ASMJIT_ENUM(X86Features) {
kX86FeatureI486 = 1, //!< CPU is at least I486.
kX86FeatureNX, //!< CPU has Not-Execute-Bit.
kX86FeatureMT, //!< CPU has multi-threading.
kX86FeatureALTMOVCR8, //!< CPU supports `LOCK MOV CR8` (AMD CPUs).
kX86FeatureCMOV, //!< CPU has CMOV.
kX86FeatureCMPXCHG8B, //!< CPU has CMPXCHG8B.
kX86FeatureCMPXCHG16B, //!< CPU has CMPXCHG16B (x64).
kX86FeatureMSR, //!< CPU has RDMSR/WRMSR.
kX86FeatureRDTSC, //!< CPU has RDTSC.
kX86FeatureRDTSCP, //!< CPU has RDTSCP.
kX86FeatureCLFLUSH, //!< CPU has CLFUSH.
kX86FeatureCLFLUSHOPT, //!< CPU has CLFUSHOPT.
kX86FeatureCLWB, //!< CPU has CLWB.
kX86FeatureCLZERO, //!< CPU has CLZERO.
kX86FeaturePCOMMIT, //!< CPU has PCOMMIT.
kX86FeaturePREFETCHW, //!< CPU has PREFETCHW.
kX86FeaturePREFETCHWT1, //!< CPU has PREFETCHWT1.
kX86FeatureLAHFSAHF, //!< CPU has LAHF/SAHF.
kX86FeatureFXSR, //!< CPU has FXSAVE/FXRSTOR.
kX86FeatureFXSROPT, //!< CPU has FXSAVE/FXRSTOR (optimized).
kX86FeatureMMX, //!< CPU has MMX.
kX86FeatureMMX2, //!< CPU has extended MMX.
kX86Feature3DNOW, //!< CPU has 3DNOW.
kX86Feature3DNOW2, //!< CPU has 3DNOW2 (enhanced).
kX86FeatureGEODE, //!< CPU has GEODE extensions (few additions to 3DNOW).
kX86FeatureSSE, //!< CPU has SSE.
kX86FeatureSSE2, //!< CPU has SSE2.
kX86FeatureSSE3, //!< CPU has SSE3.
kX86FeatureSSSE3, //!< CPU has SSSE3.
kX86FeatureSSE4A, //!< CPU has SSE4.A.
kX86FeatureSSE4_1, //!< CPU has SSE4.1.
kX86FeatureSSE4_2, //!< CPU has SSE4.2.
kX86FeatureMSSE, //!< CPU has Misaligned SSE (MSSE).
kX86FeatureMONITOR, //!< CPU has MONITOR and MWAIT.
kX86FeatureMOVBE, //!< CPU has MOVBE.
kX86FeaturePOPCNT, //!< CPU has POPCNT.
kX86FeatureLZCNT, //!< CPU has LZCNT.
kX86FeatureAESNI, //!< CPU has AESNI.
kX86FeaturePCLMULQDQ, //!< CPU has PCLMULQDQ.
kX86FeatureRDRAND, //!< CPU has RDRAND.
kX86FeatureRDSEED, //!< CPU has RDSEED.
kX86FeatureSMAP, //!< CPU has SMAP (supervisor-mode access prevention).
kX86FeatureSMEP, //!< CPU has SMEP (supervisor-mode execution prevention).
kX86FeatureSHA, //!< CPU has SHA-1 and SHA-256.
kX86FeatureXSAVE, //!< CPU has XSAVE support (XSAVE/XRSTOR, XSETBV/XGETBV, and XCR).
kX86FeatureXSAVEC, //!< CPU has XSAVEC support (XSAVEC).
kX86FeatureXSAVES, //!< CPU has XSAVES support (XSAVES/XRSTORS).
kX86FeatureXSAVEOPT, //!< CPU has XSAVEOPT support (XSAVEOPT/XSAVEOPT64).
kX86FeatureOSXSAVE, //!< CPU has XSAVE enabled by OS.
kX86FeatureAVX, //!< CPU has AVX.
kX86FeatureAVX2, //!< CPU has AVX2.
kX86FeatureF16C, //!< CPU has F16C.
kX86FeatureFMA, //!< CPU has FMA.
kX86FeatureFMA4, //!< CPU has FMA4.
kX86FeatureXOP, //!< CPU has XOP.
kX86FeatureBMI, //!< CPU has BMI (bit manipulation instructions #1).
kX86FeatureBMI2, //!< CPU has BMI2 (bit manipulation instructions #2).
kX86FeatureADX, //!< CPU has ADX (multi-precision add-carry instruction extensions).
kX86FeatureTBM, //!< CPU has TBM (trailing bit manipulation).
kX86FeatureMPX, //!< CPU has MPX (memory protection extensions).
kX86FeatureHLE, //!< CPU has HLE.
kX86FeatureRTM, //!< CPU has RTM.
kX86FeatureTSX, //!< CPU has TSX.
kX86FeatureERMS, //!< CPU has ERMS (enhanced REP MOVSB/STOSB).
kX86FeatureFSGSBASE, //!< CPU has FSGSBASE.
kX86FeatureAVX512_F, //!< CPU has AVX512-F (foundation).
kX86FeatureAVX512_CDI, //!< CPU has AVX512-CDI (conflict detection).
kX86FeatureAVX512_PFI, //!< CPU has AVX512-PFI (prefetch instructions).
kX86FeatureAVX512_ERI, //!< CPU has AVX512-ERI (exponential and reciprocal).
kX86FeatureAVX512_DQ, //!< CPU has AVX512-DQ (DWORD/QWORD).
kX86FeatureAVX512_BW, //!< CPU has AVX512-BW (BYTE/WORD).
kX86FeatureAVX512_VL, //!< CPU has AVX512-VL (vector length extensions).
kX86FeatureAVX512_IFMA, //!< CPU has AVX512-IFMA (integer fused-multiply-add using 52-bit precision).
kX86FeatureAVX512_VBMI, //!< CPU has AVX512-VBMI (vector byte manipulation).
kX86FeatureAVX512_VPOPCNTDQ, //!< CPU has AVX512-VPOPCNTDQ (VPOPCNT[D|Q] instructions).
kX86FeatureAVX512_4VNNIW, //!< CPU has AVX512-VNNIW (vector NN instructions word variable precision).
kX86FeatureAVX512_4FMAPS, //!< CPU has AVX512-FMAPS (FMA packed single).
kX86FeaturesCount //!< Count of X86/X64 CPU features.
};
// --------------------------------------------------------------------------
// [ArmInfo]
// --------------------------------------------------------------------------
struct ArmData {
};
// --------------------------------------------------------------------------
// [X86Info]
// --------------------------------------------------------------------------
struct X86Data {
uint32_t _processorType; //!< Processor type.
uint32_t _brandIndex; //!< Brand index.
uint32_t _flushCacheLineSize; //!< Flush cache line size (in bytes).
uint32_t _maxLogicalProcessors; //!< Maximum number of addressable IDs for logical processors.
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE CpuInfo() noexcept { reset(); }
ASMJIT_INLINE CpuInfo(const CpuInfo& other) noexcept { init(other); }
// --------------------------------------------------------------------------
// [Init / Reset]
// --------------------------------------------------------------------------
//! Initialize CpuInfo to the given architecture, see \ArchInfo.
ASMJIT_INLINE void initArch(uint32_t archType, uint32_t archMode = 0) noexcept {
_archInfo.init(archType, archMode);
}
ASMJIT_INLINE void init(const CpuInfo& other) noexcept { ::memcpy(this, &other, sizeof(*this)); }
ASMJIT_INLINE void reset() noexcept { ::memset(this, 0, sizeof(*this)); }
// --------------------------------------------------------------------------
// [Detect]
// --------------------------------------------------------------------------
ASMJIT_API void detect() noexcept;
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get generic architecture information.
ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _archInfo; }
//! Get CPU architecture type, see \ArchInfo::Type.
ASMJIT_INLINE uint32_t getArchType() const noexcept { return _archInfo.getType(); }
//! Get CPU architecture sub-type, see \ArchInfo::SubType.
ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return _archInfo.getSubType(); }
//! Get CPU vendor ID.
ASMJIT_INLINE uint32_t getVendorId() const noexcept { return _vendorId; }
//! Get CPU family ID.
ASMJIT_INLINE uint32_t getFamily() const noexcept { return _family; }
//! Get CPU model ID.
ASMJIT_INLINE uint32_t getModel() const noexcept { return _model; }
//! Get CPU stepping.
ASMJIT_INLINE uint32_t getStepping() const noexcept { return _stepping; }
//! Get number of hardware threads available.
ASMJIT_INLINE uint32_t getHwThreadsCount() const noexcept {
return _hwThreadsCount;
}
//! Get all CPU features.
ASMJIT_INLINE const CpuFeatures& getFeatures() const noexcept { return _features; }
//! Get whether CPU has a `feature`.
ASMJIT_INLINE bool hasFeature(uint32_t feature) const noexcept { return _features.has(feature); }
//! Add a CPU `feature`.
ASMJIT_INLINE CpuInfo& addFeature(uint32_t feature) noexcept { _features.add(feature); return *this; }
//! Get CPU vendor string.
ASMJIT_INLINE const char* getVendorString() const noexcept { return _vendorString; }
//! Get CPU brand string.
ASMJIT_INLINE const char* getBrandString() const noexcept { return _brandString; }
// --------------------------------------------------------------------------
// [Accessors - ARM]
// --------------------------------------------------------------------------
// --------------------------------------------------------------------------
// [Accessors - X86]
// --------------------------------------------------------------------------
//! Get processor type.
ASMJIT_INLINE uint32_t getX86ProcessorType() const noexcept {
return _x86Data._processorType;
}
//! Get brand index.
ASMJIT_INLINE uint32_t getX86BrandIndex() const noexcept {
return _x86Data._brandIndex;
}
//! Get flush cache line size.
ASMJIT_INLINE uint32_t getX86FlushCacheLineSize() const noexcept {
return _x86Data._flushCacheLineSize;
}
//! Get maximum logical processors count.
ASMJIT_INLINE uint32_t getX86MaxLogicalProcessors() const noexcept {
return _x86Data._maxLogicalProcessors;
}
// --------------------------------------------------------------------------
// [Statics]
// --------------------------------------------------------------------------
//! Get the host CPU information.
ASMJIT_API static const CpuInfo& getHost() noexcept;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
ArchInfo _archInfo; //!< CPU architecture information.
uint32_t _vendorId; //!< CPU vendor id, see \ref Vendor.
uint32_t _family; //!< CPU family ID.
uint32_t _model; //!< CPU model ID.
uint32_t _stepping; //!< CPU stepping.
uint32_t _hwThreadsCount; //!< Number of hardware threads.
CpuFeatures _features; //!< CPU features.
char _vendorString[16]; //!< CPU vendor string.
char _brandString[64]; //!< CPU brand string.
// Architecture specific data.
union {
ArmData _armData;
X86Data _x86Data;
};
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CPUINFO_H

View File

@ -1,186 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies]
#include "../base/arch.h"
#include "../base/func.h"
#if defined(ASMJIT_BUILD_X86)
#include "../x86/x86internal_p.h"
#include "../x86/x86operand.h"
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
#include "../arm/arminternal_p.h"
#include "../arm/armoperand.h"
#endif // ASMJIT_BUILD_ARM
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::CallConv - Init / Reset]
// ============================================================================
ASMJIT_FAVOR_SIZE Error CallConv::init(uint32_t ccId) noexcept {
reset();
#if defined(ASMJIT_BUILD_X86)
if (CallConv::isX86Family(ccId))
return X86Internal::initCallConv(*this, ccId);
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
if (CallConv::isArmFamily(ccId))
return ArmInternal::initCallConv(*this, ccId);
#endif // ASMJIT_BUILD_ARM
return DebugUtils::errored(kErrorInvalidArgument);
}
// ============================================================================
// [asmjit::FuncDetail - Init / Reset]
// ============================================================================
ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& sign) {
uint32_t ccId = sign.getCallConv();
CallConv& cc = _callConv;
uint32_t argCount = sign.getArgCount();
if (ASMJIT_UNLIKELY(argCount > kFuncArgCount))
return DebugUtils::errored(kErrorInvalidArgument);
ASMJIT_PROPAGATE(cc.init(ccId));
uint32_t gpSize = (cc.getArchType() == ArchInfo::kTypeX86) ? 4 : 8;
uint32_t deabstractDelta = TypeId::deabstractDeltaOfSize(gpSize);
const uint8_t* args = sign.getArgs();
for (uint32_t i = 0; i < argCount; i++) {
Value& arg = _args[i];
arg.initTypeId(TypeId::deabstract(args[i], deabstractDelta));
}
_argCount = static_cast<uint8_t>(argCount);
uint32_t ret = sign.getRet();
if (ret != TypeId::kVoid) {
_rets[0].initTypeId(TypeId::deabstract(ret, deabstractDelta));
_retCount = 1;
}
#if defined(ASMJIT_BUILD_X86)
if (CallConv::isX86Family(ccId))
return X86Internal::initFuncDetail(*this, sign, gpSize);
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
if (CallConv::isArmFamily(ccId))
return ArmInternal::initFuncDetail(*this, sign, gpSize);
#endif // ASMJIT_BUILD_ARM
// We should never bubble here as if `cc.init()` succeeded then there has to
// be an implementation for the current architecture. However, stay safe.
return DebugUtils::errored(kErrorInvalidArgument);
}
// ============================================================================
// [asmjit::FuncFrameLayout - Init / Reset]
// ============================================================================
ASMJIT_FAVOR_SIZE Error FuncFrameLayout::init(const FuncDetail& func, const FuncFrameInfo& ffi) noexcept {
uint32_t ccId = func.getCallConv().getId();
#if defined(ASMJIT_BUILD_X86)
if (CallConv::isX86Family(ccId))
return X86Internal::initFrameLayout(*this, func, ffi);
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
if (CallConv::isArmFamily(ccId))
return ArmInternal::initFrameLayout(*this, func, ffi);
#endif // ASMJIT_BUILD_ARM
return DebugUtils::errored(kErrorInvalidArgument);
}
// ============================================================================
// [asmjit::FuncArgsMapper]
// ============================================================================
ASMJIT_FAVOR_SIZE Error FuncArgsMapper::updateFrameInfo(FuncFrameInfo& ffi) const noexcept {
const FuncDetail* func = getFuncDetail();
if (!func) return DebugUtils::errored(kErrorInvalidState);
uint32_t ccId = func->getCallConv().getId();
#if defined(ASMJIT_BUILD_X86)
if (CallConv::isX86Family(ccId))
return X86Internal::argsToFrameInfo(*this, ffi);
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
if (CallConv::isArmFamily(ccId))
return ArmInternal::argsToFrameInfo(*this, ffi);
#endif // ASMJIT_BUILD_X86
return DebugUtils::errored(kErrorInvalidArch);
}
// ============================================================================
// [asmjit::FuncUtils]
// ============================================================================
ASMJIT_FAVOR_SIZE Error FuncUtils::emitProlog(CodeEmitter* emitter, const FuncFrameLayout& layout) {
#if defined(ASMJIT_BUILD_X86)
if (emitter->getArchInfo().isX86Family())
return X86Internal::emitProlog(static_cast<X86Emitter*>(emitter), layout);
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
if (emitter->getArchInfo().isArmFamily())
return ArmInternal::emitProlog(static_cast<ArmEmitter*>(emitter), layout);
#endif // ASMJIT_BUILD_ARM
return DebugUtils::errored(kErrorInvalidArch);
}
ASMJIT_FAVOR_SIZE Error FuncUtils::emitEpilog(CodeEmitter* emitter, const FuncFrameLayout& layout) {
#if defined(ASMJIT_BUILD_X86)
if (emitter->getArchInfo().isX86Family())
return X86Internal::emitEpilog(static_cast<X86Emitter*>(emitter), layout);
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
if (emitter->getArchInfo().isArmFamily())
return ArmInternal::emitEpilog(static_cast<ArmEmitter*>(emitter), layout);
#endif // ASMJIT_BUILD_ARM
return DebugUtils::errored(kErrorInvalidArch);
}
ASMJIT_FAVOR_SIZE Error FuncUtils::allocArgs(CodeEmitter* emitter, const FuncFrameLayout& layout, const FuncArgsMapper& args) {
#if defined(ASMJIT_BUILD_X86)
if (emitter->getArchInfo().isX86Family())
return X86Internal::allocArgs(static_cast<X86Emitter*>(emitter), layout, args);
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
if (emitter->getArchInfo().isArmFamily())
return ArmInternal::allocArgs(static_cast<ArmEmitter*>(emitter), layout, args);
#endif // ASMJIT_BUILD_ARM
return DebugUtils::errored(kErrorInvalidArch);
}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"

View File

@ -1,118 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies]
#include "../base/globals.h"
#include "../base/utils.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::DebugUtils]
// ============================================================================
#if !defined(ASMJIT_DISABLE_TEXT)
static const char errorMessages[] =
"Ok\0"
"No heap memory\0"
"No virtual memory\0"
"Invalid argument\0"
"Invalid state\0"
"Invalid architecture\0"
"Not initialized\0"
"Already initialized\0"
"Feature not enabled\0"
"Slot occupied\0"
"No code generated\0"
"Code too large\0"
"Invalid label\0"
"Label index overflow\0"
"Label already bound\0"
"Label already defined\0"
"Label name too long\0"
"Invalid label name\0"
"Invalid parent label\0"
"Non-local label can't have parent\0"
"Relocation index overflow\0"
"Invalid relocation entry\0"
"Invalid instruction\0"
"Invalid register type\0"
"Invalid register kind\0"
"Invalid register's physical id\0"
"Invalid register's virtual id\0"
"Invalid prefix combination\0"
"Invalid lock prefix\0"
"Invalid xacquire prefix\0"
"Invalid xrelease prefix\0"
"Invalid rep prefix\0"
"Invalid rex prefix\0"
"Invalid mask, expected {k}\0"
"Invalid use of {k}\0"
"Invalid use of {k}{z}\0"
"Invalid broadcast {1tox}\0"
"Invalid {er} or {sae} option\0"
"Invalid address\0"
"Invalid address index\0"
"Invalid address scale\0"
"Invalid use of 64-bit address\0"
"Invalid displacement\0"
"Invalid segment\0"
"Invalid immediate value\0"
"Invalid operand size\0"
"Ambiguous operand size\0"
"Operand size mismatch\0"
"Invalid type-info\0"
"Invalid use of a low 8-bit GPB register\0"
"Invalid use of a 64-bit GPQ register in 32-bit mode\0"
"Invalid use of an 80-bit float\0"
"Not consecutive registers\0"
"No more physical registers\0"
"Overlapped registers\0"
"Overlapping register and arguments base-address register\0"
"Unknown error\0";
#endif // ASMJIT_DISABLE_TEXT
ASMJIT_FAVOR_SIZE const char* DebugUtils::errorAsString(Error err) noexcept {
#if !defined(ASMJIT_DISABLE_TEXT)
return Utils::findPackedString(errorMessages, std::min<Error>(err, kErrorCount));
#else
static const char noMessage[] = "";
return noMessage;
#endif
}
ASMJIT_FAVOR_SIZE void DebugUtils::debugOutput(const char* str) noexcept {
#if ASMJIT_OS_WINDOWS
::OutputDebugStringA(str);
#else
::fputs(str, stderr);
#endif
}
ASMJIT_FAVOR_SIZE void DebugUtils::assertionFailed(const char* file, int line, const char* msg) noexcept {
char str[1024];
snprintf(str, 1024,
"[asmjit] Assertion failed at %s (line %d):\n"
"[asmjit] %s\n", file, line, msg);
// Support buggy `snprintf` implementations.
str[1023] = '\0';
debugOutput(str);
::abort();
}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"

View File

@ -1,341 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_GLOBALS_H
#define _ASMJIT_BASE_GLOBALS_H
// [Dependencies]
#include "../asmjit_build.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [asmjit::Globals]
// ============================================================================
enum { kInvalidValue = 0xFFFFFFFFU };
//! AsmJit globals.
namespace Globals {
//! Invalid index
//!
//! Invalid index is the last possible index that is never used in practice. In
//! AsmJit it is used exclusively with strings to indicate the the length of the
//! string is not known and has to be determined.
static const size_t kInvalidIndex = ~static_cast<size_t>(0);
//! Invalid base address.
static const uint64_t kNoBaseAddress = ~static_cast<uint64_t>(0);
//! Global definitions.
ASMJIT_ENUM(Defs) {
//! Invalid register id.
kInvalidRegId = 0xFF,
//! Host memory allocator overhead.
kAllocOverhead = static_cast<int>(sizeof(intptr_t) * 4),
//! Aggressive growing strategy threshold.
kAllocThreshold = 8192 * 1024
};
ASMJIT_ENUM(Limits) {
//! Count of register kinds that are important to Function API and CodeCompiler.
//! The target architecture can define more register kinds for special registers,
//! but these will never map to virtual registers and will never be used to pass
//! and return function arguments and function return values, respectively.
kMaxVRegKinds = 4,
//! Maximum number of physical registers of all kinds of all supported
//! architectures. This is only important for \ref CodeCompiler and its
//! \ref RAPass (register allocator pass).
//!
//! NOTE: The distribution of these registers is architecture specific.
kMaxPhysRegs = 64,
//! Maximum alignment.
kMaxAlignment = 64,
//! Maximum label or symbol length in bytes (take into consideration that a
//! single UTF-8 character can take more than single byte to encode it).
kMaxLabelLength = 2048
};
} // Globals namespace
// ============================================================================
// [asmjit::Error]
// ============================================================================
//! AsmJit error type (uint32_t).
typedef uint32_t Error;
//! AsmJit error codes.
ASMJIT_ENUM(ErrorCode) {
//! No error (success).
//!
//! This is default state and state you want.
kErrorOk = 0,
//! Heap memory allocation failed.
kErrorNoHeapMemory,
//! Virtual memory allocation failed.
kErrorNoVirtualMemory,
//! Invalid argument.
kErrorInvalidArgument,
//! Invalid state.
//!
//! If this error is returned it means that either you are doing something
//! wrong or AsmJit caught itself by doing something wrong. This error should
//! not be underestimated.
kErrorInvalidState,
//! Invalid or incompatible architecture.
kErrorInvalidArch,
//! The object is not initialized.
kErrorNotInitialized,
//! The object is already initialized.
kErrorAlreadyInitialized,
//! Built-in feature was disabled at compile time and it's not available.
kErrorFeatureNotEnabled,
//! CodeHolder can't have attached more than one \ref Assembler at a time.
kErrorSlotOccupied,
//! No code generated.
//!
//! Returned by runtime if the \ref CodeHolder contains no code.
kErrorNoCodeGenerated,
//! Code generated is larger than allowed.
kErrorCodeTooLarge,
//! Attempt to use uninitialized label.
kErrorInvalidLabel,
//! Label index overflow - a single `Assembler` instance can hold more than
//! 2 billion labels (2147483391 to be exact). If there is an attempt to
//! create more labels this error is returned.
kErrorLabelIndexOverflow,
//! Label is already bound.
kErrorLabelAlreadyBound,
//! Label is already defined (named labels).
kErrorLabelAlreadyDefined,
//! Label name is too long.
kErrorLabelNameTooLong,
//! Label must always be local if it's anonymous (without a name).
kErrorInvalidLabelName,
//! Parent id passed to `CodeHolder::newNamedLabelId()` was invalid.
kErrorInvalidParentLabel,
//! Parent id specified for a non-local (global) label.
kErrorNonLocalLabelCantHaveParent,
//! Relocation index overflow.
kErrorRelocIndexOverflow,
//! Invalid relocation entry.
kErrorInvalidRelocEntry,
//! Invalid instruction.
kErrorInvalidInstruction,
//! Invalid register type.
kErrorInvalidRegType,
//! Invalid register kind.
kErrorInvalidRegKind,
//! Invalid register's physical id.
kErrorInvalidPhysId,
//! Invalid register's virtual id.
kErrorInvalidVirtId,
//! Invalid prefix combination.
kErrorInvalidPrefixCombination,
//! Invalid LOCK prefix.
kErrorInvalidLockPrefix,
//! Invalid XACQUIRE prefix.
kErrorInvalidXAcquirePrefix,
//! Invalid XACQUIRE prefix.
kErrorInvalidXReleasePrefix,
//! Invalid REP prefix.
kErrorInvalidRepPrefix,
//! Invalid REX prefix.
kErrorInvalidRexPrefix,
//! Invalid mask register (not 'k').
kErrorInvalidKMaskReg,
//! Invalid {k} use (not supported by the instruction).
kErrorInvalidKMaskUse,
//! Invalid {k}{z} use (not supported by the instruction).
kErrorInvalidKZeroUse,
//! Invalid broadcast - Currently only related to invalid use of AVX-512 {1tox}.
kErrorInvalidBroadcast,
//! Invalid 'embedded-rounding' {er} or 'suppress-all-exceptions' {sae} (AVX-512).
kErrorInvalidEROrSAE,
//! Invalid address used (not encodable).
kErrorInvalidAddress,
//! Invalid index register used in memory address (not encodable).
kErrorInvalidAddressIndex,
//! Invalid address scale (not encodable).
kErrorInvalidAddressScale,
//! Invalid use of 64-bit address.
kErrorInvalidAddress64Bit,
//! Invalid displacement (not encodable).
kErrorInvalidDisplacement,
//! Invalid segment (X86).
kErrorInvalidSegment,
//! Invalid immediate (out of bounds on X86 and invalid pattern on ARM).
kErrorInvalidImmediate,
//! Invalid operand size.
kErrorInvalidOperandSize,
//! Ambiguous operand size (memory has zero size while it's required to determine the operation type.
kErrorAmbiguousOperandSize,
//! Mismatching operand size (size of multiple operands doesn't match the operation size).
kErrorOperandSizeMismatch,
//! Invalid TypeId.
kErrorInvalidTypeId,
//! Invalid use of a 8-bit GPB-HIGH register.
kErrorInvalidUseOfGpbHi,
//! Invalid use of a 64-bit GPQ register in 32-bit mode.
kErrorInvalidUseOfGpq,
//! Invalid use of an 80-bit float (TypeId::kF80).
kErrorInvalidUseOfF80,
//! Some registers in the instruction muse be consecutive (some ARM and AVX512 neural-net instructions).
kErrorNotConsecutiveRegs,
//! AsmJit requires a physical register, but no one is available.
kErrorNoMorePhysRegs,
//! A variable has been assigned more than once to a function argument (CodeCompiler).
kErrorOverlappedRegs,
//! Invalid register to hold stack arguments offset.
kErrorOverlappingStackRegWithRegArg,
//! Count of AsmJit error codes.
kErrorCount
};
// ============================================================================
// [asmjit::Internal]
// ============================================================================
namespace Internal {
#if defined(ASMJIT_CUSTOM_ALLOC) && \
defined(ASMJIT_CUSTOM_REALLOC) && \
defined(ASMJIT_CUSTOM_FREE)
static ASMJIT_INLINE void* allocMemory(size_t size) noexcept { return ASMJIT_CUSTOM_ALLOC(size); }
static ASMJIT_INLINE void* reallocMemory(void* p, size_t size) noexcept { return ASMJIT_CUSTOM_REALLOC(p, size); }
static ASMJIT_INLINE void releaseMemory(void* p) noexcept { ASMJIT_CUSTOM_FREE(p); }
#elif !defined(ASMJIT_CUSTOM_ALLOC) && \
!defined(ASMJIT_CUSTOM_REALLOC) && \
!defined(ASMJIT_CUSTOM_FREE)
static ASMJIT_INLINE void* allocMemory(size_t size) noexcept { return ::malloc(size); }
static ASMJIT_INLINE void* reallocMemory(void* p, size_t size) noexcept { return ::realloc(p, size); }
static ASMJIT_INLINE void releaseMemory(void* p) noexcept { ::free(p); }
#else
# error "[asmjit] You must provide either none or all of ASMJIT_CUSTOM_[ALLOC|REALLOC|FREE]"
#endif
//! Cast designed to cast between function and void* pointers.
template<typename Dst, typename Src>
static ASMJIT_INLINE Dst ptr_cast(Src p) noexcept { return (Dst)p; }
} // Internal namespace
template<typename Func>
static ASMJIT_INLINE Func ptr_as_func(void* func) noexcept { return Internal::ptr_cast<Func, void*>(func); }
template<typename Func>
static ASMJIT_INLINE void* func_as_ptr(Func func) noexcept { return Internal::ptr_cast<void*, Func>(func); }
// ============================================================================
// [asmjit::DebugUtils]
// ============================================================================
namespace DebugUtils {
//! Returns the error `err` passed.
//!
//! Provided for debugging purposes. Putting a breakpoint inside `errored` can
//! help with tracing the origin of any error reported / returned by AsmJit.
static ASMJIT_INLINE Error errored(Error err) noexcept { return err; }
//! Get a printable version of `asmjit::Error` code.
ASMJIT_API const char* errorAsString(Error err) noexcept;
//! Called to output debugging message(s).
ASMJIT_API void debugOutput(const char* str) noexcept;
//! Called on assertion failure.
//!
//! \param file Source file name where it happened.
//! \param line Line in the source file.
//! \param msg Message to display.
//!
//! If you have problems with assertions put a breakpoint at assertionFailed()
//! function (asmjit/base/globals.cpp) and check the call stack to locate the
//! failing code.
ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, const char* msg) noexcept;
#if defined(ASMJIT_DEBUG)
# define ASMJIT_ASSERT(exp) \
do { \
if (ASMJIT_LIKELY(exp)) \
break; \
::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, #exp); \
} while (0)
# define ASMJIT_NOT_REACHED() \
do { \
::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, \
"ASMJIT_NOT_REACHED has been reached"); \
ASMJIT_ASSUME(0); \
} while (0)
#else
# define ASMJIT_ASSERT(exp) ASMJIT_NOP
# define ASMJIT_NOT_REACHED() ASMJIT_ASSUME(0)
#endif // DEBUG
//! \internal
//!
//! Used by AsmJit to propagate a possible `Error` produced by `...` to the caller.
#define ASMJIT_PROPAGATE(...) \
do { \
::asmjit::Error _err = __VA_ARGS__; \
if (ASMJIT_UNLIKELY(_err)) \
return _err; \
} while (0)
} // DebugUtils namespace
// ============================================================================
// [asmjit::Init / NoInit]
// ============================================================================
#if !defined(ASMJIT_DOCGEN)
struct _Init {};
static const _Init Init = {};
struct _NoInit {};
static const _NoInit NoInit = {};
#endif // !ASMJIT_DOCGEN
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_GLOBALS_H

View File

@ -1,77 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Guard]
#include "../asmjit_build.h"
#if defined(ASMJIT_BUILD_X86)
// [Dependencies]
#include "../base/arch.h"
#include "../base/inst.h"
#if defined(ASMJIT_BUILD_X86)
# include "../x86/x86instimpl_p.h"
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
# include "../arm/arminstimpl_p.h"
#endif // ASMJIT_BUILD_ARM
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::Inst - Validate]
// ============================================================================
#if !defined(ASMJIT_DISABLE_VALIDATION)
Error Inst::validate(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count) noexcept {
#if defined(ASMJIT_BUILD_X86)
if (ArchInfo::isX86Family(archType))
return X86InstImpl::validate(archType, detail, operands, count);
#endif
#if defined(ASMJIT_BUILD_ARM)
if (ArchInfo::isArmFamily(archType))
return ArmInstImpl::validate(archType, detail, operands, count);
#endif
return DebugUtils::errored(kErrorInvalidArch);
}
#endif
// ============================================================================
// [asmjit::Inst - CheckFeatures]
// ============================================================================
#if !defined(ASMJIT_DISABLE_EXTENSIONS)
Error Inst::checkFeatures(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count, CpuFeatures& out) noexcept {
#if defined(ASMJIT_BUILD_X86)
if (ArchInfo::isX86Family(archType))
return X86InstImpl::checkFeatures(archType, detail, operands, count, out);
#endif
#if defined(ASMJIT_BUILD_ARM)
if (ArchInfo::isArmFamily(archType))
return ArmInstImpl::checkFeatures(archType, detail, operands, count, out);
#endif
return DebugUtils::errored(kErrorInvalidArch);
}
#endif // !defined(ASMJIT_DISABLE_EXTENSIONS)
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // ASMJIT_BUILD_X86

View File

@ -1,108 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_INST_H
#define _ASMJIT_BASE_INST_H
// [Dependencies]
#include "../base/cpuinfo.h"
#include "../base/operand.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [asmjit::Inst]
// ============================================================================
//! Definitions and utilities related to instructions used by all architectures.
struct Inst {
ASMJIT_ENUM(Id) {
kIdNone = 0 //!< Invalid or uninitialized instruction id.
};
//! Describes an instruction's jump type, if any.
ASMJIT_ENUM(JumpType) {
kJumpTypeNone = 0, //!< Instruction doesn't jump (regular instruction).
kJumpTypeDirect = 1, //!< Instruction is a unconditional (direct) jump.
kJumpTypeConditional = 2, //!< Instruction is a conditional jump.
kJumpTypeCall = 3, //!< Instruction is a function call.
kJumpTypeReturn = 4 //!< Instruction is a function return.
};
// --------------------------------------------------------------------------
// [Detail]
// --------------------------------------------------------------------------
//! Instruction id, options, and extraReg packed in a single structure. This
//! structure exists to simplify analysis and validation API that requires a
//! lot of information about the instruction to be processed.
class Detail {
public:
ASMJIT_INLINE Detail() noexcept
: instId(0),
options(0),
extraReg() {}
explicit ASMJIT_INLINE Detail(uint32_t instId, uint32_t options = 0) noexcept
: instId(instId),
options(options),
extraReg() {}
ASMJIT_INLINE Detail(uint32_t instId, uint32_t options, const RegOnly& reg) noexcept
: instId(instId),
options(options),
extraReg(reg) {}
ASMJIT_INLINE Detail(uint32_t instId, uint32_t options, const Reg& reg) noexcept
: instId(instId),
options(options) { extraReg.init(reg); }
// ------------------------------------------------------------------------
// [Accessors]
// ------------------------------------------------------------------------
ASMJIT_INLINE bool hasExtraReg() const noexcept { return extraReg.isValid(); }
// ------------------------------------------------------------------------
// [Members]
// ------------------------------------------------------------------------
uint32_t instId;
uint32_t options;
RegOnly extraReg;
};
// --------------------------------------------------------------------------
// [API]
// --------------------------------------------------------------------------
#if !defined(ASMJIT_DISABLE_VALIDATION)
//! Validate the given instruction.
ASMJIT_API static Error validate(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count) noexcept;
#endif // !ASMJIT_DISABLE_VALIDATION
#if !defined(ASMJIT_DISABLE_EXTENSIONS)
//! Check CPU features required to execute the given instruction.
ASMJIT_API static Error checkFeatures(uint32_t archType, const Detail& detail, const Operand_* operands, uint32_t count, CpuFeatures& out) noexcept;
#endif // !defined(ASMJIT_DISABLE_EXTENSIONS)
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_INST_H

View File

@ -1,497 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Guard]
#include "../asmjit_build.h"
#if !defined(ASMJIT_DISABLE_LOGGING)
// [Dependencies]
#include "../base/codeholder.h"
#include "../base/codeemitter.h"
#include "../base/logging.h"
#include "../base/utils.h"
#if !defined(ASMJIT_DISABLE_BUILDER)
# include "../base/codebuilder.h"
#endif // !ASMJIT_DISABLE_BUILDER
#if !defined(ASMJIT_DISABLE_COMPILER)
# include "../base/codecompiler.h"
#else
namespace asmjit { class VirtReg; }
#endif // !ASMJIT_DISABLE_COMPILER
#if defined(ASMJIT_BUILD_X86)
# include "../x86/x86logging_p.h"
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
# include "../arm/armlogging_p.h"
#endif // ASMJIT_BUILD_ARM
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::Logger - Construction / Destruction]
// ============================================================================
Logger::Logger() noexcept {
_options = 0;
::memset(_indentation, 0, ASMJIT_ARRAY_SIZE(_indentation));
}
Logger::~Logger() noexcept {}
// ============================================================================
// [asmjit::Logger - Logging]
// ============================================================================
Error Logger::logf(const char* fmt, ...) noexcept {
Error err;
va_list ap;
va_start(ap, fmt);
err = logv(fmt, ap);
va_end(ap);
return err;
}
Error Logger::logv(const char* fmt, va_list ap) noexcept {
char buf[1024];
size_t len = vsnprintf(buf, sizeof(buf), fmt, ap);
if (len >= sizeof(buf))
len = sizeof(buf) - 1;
return log(buf, len);
}
Error Logger::logBinary(const void* data, size_t size) noexcept {
static const char prefix[] = ".data ";
static const char hex[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
const uint8_t* s = static_cast<const uint8_t*>(data);
size_t i = size;
char buffer[128];
::memcpy(buffer, prefix, ASMJIT_ARRAY_SIZE(prefix) - 1);
while (i) {
uint32_t n = static_cast<uint32_t>(std::min<size_t>(i, 16));
char* p = buffer + ASMJIT_ARRAY_SIZE(prefix) - 1;
i -= n;
do {
uint32_t c = s[0];
p[0] = hex[c >> 4];
p[1] = hex[c & 15];
p += 2;
s += 1;
} while (--n);
*p++ = '\n';
ASMJIT_PROPAGATE(log(buffer, (size_t)(p - buffer)));
}
return kErrorOk;
}
// ============================================================================
// [asmjit::Logger - Indentation]
// ============================================================================
void Logger::setIndentation(const char* indentation) noexcept {
::memset(_indentation, 0, ASMJIT_ARRAY_SIZE(_indentation));
if (!indentation)
return;
size_t length = Utils::strLen(indentation, ASMJIT_ARRAY_SIZE(_indentation) - 1);
::memcpy(_indentation, indentation, length);
}
// ============================================================================
// [asmjit::FileLogger - Construction / Destruction]
// ============================================================================
FileLogger::FileLogger(FILE* stream) noexcept : _stream(nullptr) { setStream(stream); }
FileLogger::~FileLogger() noexcept {}
// ============================================================================
// [asmjit::FileLogger - Logging]
// ============================================================================
Error FileLogger::_log(const char* buf, size_t len) noexcept {
if (!_stream)
return kErrorOk;
if (len == Globals::kInvalidIndex)
len = strlen(buf);
fwrite(buf, 1, len, _stream);
return kErrorOk;
}
// ============================================================================
// [asmjit::StringLogger - Construction / Destruction]
// ============================================================================
StringLogger::StringLogger() noexcept {}
StringLogger::~StringLogger() noexcept {}
// ============================================================================
// [asmjit::StringLogger - Logging]
// ============================================================================
Error StringLogger::_log(const char* buf, size_t len) noexcept {
return _stringBuilder.appendString(buf, len);
}
// ============================================================================
// [asmjit::Logging]
// ============================================================================
Error Logging::formatLabel(
StringBuilder& sb,
uint32_t logOptions,
const CodeEmitter* emitter,
uint32_t labelId) noexcept {
const LabelEntry* le = emitter->getCode()->getLabelEntry(labelId);
if (ASMJIT_UNLIKELY(!le))
return sb.appendFormat("InvalidLabel[Id=%u]", static_cast<unsigned int>(labelId));
if (le->hasName()) {
if (le->hasParent()) {
uint32_t parentId = le->getParentId();
const LabelEntry* pe = emitter->getCode()->getLabelEntry(parentId);
if (ASMJIT_UNLIKELY(!pe))
ASMJIT_PROPAGATE(sb.appendFormat("InvalidLabel[Id=%u]", static_cast<unsigned int>(labelId)));
else if (ASMJIT_UNLIKELY(!pe->hasName()))
ASMJIT_PROPAGATE(sb.appendFormat("L%u", Operand::unpackId(parentId)));
else
ASMJIT_PROPAGATE(sb.appendString(pe->getName()));
ASMJIT_PROPAGATE(sb.appendChar('.'));
}
return sb.appendString(le->getName());
}
else {
return sb.appendFormat("L%u", Operand::unpackId(labelId));
}
}
Error Logging::formatRegister(
StringBuilder& sb,
uint32_t logOptions,
const CodeEmitter* emitter,
uint32_t archType,
uint32_t regType,
uint32_t regId) noexcept {
#if defined(ASMJIT_BUILD_X86)
return X86Logging::formatRegister(sb, logOptions, emitter, archType, regType, regId);
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
return ArmLogging::formatRegister(sb, logOptions, emitter, archType, regType, regId);
#endif // ASMJIT_BUILD_ARM
return kErrorInvalidArch;
}
Error Logging::formatOperand(
StringBuilder& sb,
uint32_t logOptions,
const CodeEmitter* emitter,
uint32_t archType,
const Operand_& op) noexcept {
#if defined(ASMJIT_BUILD_X86)
return X86Logging::formatOperand(sb, logOptions, emitter, archType, op);
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
return ArmLogging::formatOperand(sb, logOptions, emitter, archType, op);
#endif // ASMJIT_BUILD_ARM
return kErrorInvalidArch;
}
Error Logging::formatInstruction(
StringBuilder& sb,
uint32_t logOptions,
const CodeEmitter* emitter,
uint32_t archType,
const Inst::Detail& detail, const Operand_* opArray, uint32_t opCount) noexcept {
#if defined(ASMJIT_BUILD_X86)
return X86Logging::formatInstruction(sb, logOptions, emitter, archType, detail, opArray, opCount);
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
return ArmLogging::formatInstruction(sb, logOptions, emitter, archType, detail, opArray, opCount);
#endif // ASMJIT_BUILD_ARM
return kErrorInvalidArch;
}
#if !defined(ASMJIT_DISABLE_BUILDER)
static Error formatTypeId(StringBuilder& sb, uint32_t typeId) noexcept {
if (typeId == TypeId::kVoid)
return sb.appendString("void");
if (!TypeId::isValid(typeId))
return sb.appendString("unknown");
const char* typeName = "unknown";
uint32_t typeSize = TypeId::sizeOf(typeId);
uint32_t elementId = TypeId::elementOf(typeId);
switch (elementId) {
case TypeId::kIntPtr : typeName = "intptr" ; break;
case TypeId::kUIntPtr: typeName = "uintptr"; break;
case TypeId::kI8 : typeName = "i8" ; break;
case TypeId::kU8 : typeName = "u8" ; break;
case TypeId::kI16 : typeName = "i16" ; break;
case TypeId::kU16 : typeName = "u16" ; break;
case TypeId::kI32 : typeName = "i32" ; break;
case TypeId::kU32 : typeName = "u32" ; break;
case TypeId::kI64 : typeName = "i64" ; break;
case TypeId::kU64 : typeName = "u64" ; break;
case TypeId::kF32 : typeName = "f32" ; break;
case TypeId::kF64 : typeName = "f64" ; break;
case TypeId::kF80 : typeName = "f80" ; break;
case TypeId::kMask8 : typeName = "mask8" ; break;
case TypeId::kMask16 : typeName = "mask16" ; break;
case TypeId::kMask32 : typeName = "mask32" ; break;
case TypeId::kMask64 : typeName = "mask64" ; break;
case TypeId::kMmx32 : typeName = "mmx32" ; break;
case TypeId::kMmx64 : typeName = "mmx64" ; break;
}
uint32_t elementSize = TypeId::sizeOf(elementId);
if (typeSize > elementSize) {
unsigned int numElements = typeSize / elementSize;
return sb.appendFormat("%sx%u", typeName, numElements);
}
else {
return sb.appendString(typeName);
}
}
static Error formatFuncDetailValue(
StringBuilder& sb,
uint32_t logOptions,
const CodeEmitter* emitter,
FuncDetail::Value value) noexcept {
uint32_t typeId = value.getTypeId();
ASMJIT_PROPAGATE(formatTypeId(sb, typeId));
if (value.byReg()) {
ASMJIT_PROPAGATE(sb.appendChar(':'));
ASMJIT_PROPAGATE(Logging::formatRegister(sb, logOptions, emitter, emitter->getArchType(), value.getRegType(), value.getRegId()));
}
if (value.byStack()) {
ASMJIT_PROPAGATE(sb.appendFormat(":[%d]", static_cast<int>(value.getStackOffset())));
}
return kErrorOk;
}
static Error formatFuncRets(
StringBuilder& sb,
uint32_t logOptions,
const CodeEmitter* emitter,
const FuncDetail& fd,
VirtReg* const* vRegs) noexcept {
if (!fd.hasRet())
return sb.appendString("void");
for (uint32_t i = 0; i < fd.getRetCount(); i++) {
if (i) ASMJIT_PROPAGATE(sb.appendString(", "));
ASMJIT_PROPAGATE(formatFuncDetailValue(sb, logOptions, emitter, fd.getRet(i)));
#if !defined(ASMJIT_DISABLE_COMPILER)
if (vRegs)
ASMJIT_PROPAGATE(sb.appendFormat(" {%s}", vRegs[i]->getName()));
#endif // !ASMJIT_DISABLE_COMPILER
}
return kErrorOk;
}
static Error formatFuncArgs(
StringBuilder& sb,
uint32_t logOptions,
const CodeEmitter* emitter,
const FuncDetail& fd,
VirtReg* const* vRegs) noexcept {
for (uint32_t i = 0; i < fd.getArgCount(); i++) {
if (i) ASMJIT_PROPAGATE(sb.appendString(", "));
ASMJIT_PROPAGATE(formatFuncDetailValue(sb, logOptions, emitter, fd.getArg(i)));
#if !defined(ASMJIT_DISABLE_COMPILER)
if (vRegs)
ASMJIT_PROPAGATE(sb.appendFormat(" {%s}", vRegs[i]->getName()));
#endif // !ASMJIT_DISABLE_COMPILER
}
return kErrorOk;
}
Error Logging::formatNode(
StringBuilder& sb,
uint32_t logOptions,
const CodeBuilder* cb,
const CBNode* node_) noexcept {
if (node_->hasPosition())
ASMJIT_PROPAGATE(sb.appendFormat("<%04u> ", node_->getPosition()));
switch (node_->getType()) {
case CBNode::kNodeInst: {
const CBInst* node = node_->as<CBInst>();
ASMJIT_PROPAGATE(
Logging::formatInstruction(sb, logOptions, cb,
cb->getArchType(),
node->getInstDetail(), node->getOpArray(), node->getOpCount()));
break;
}
case CBNode::kNodeLabel: {
const CBLabel* node = node_->as<CBLabel>();
ASMJIT_PROPAGATE(sb.appendFormat("L%u:", Operand::unpackId(node->getId())));
break;
}
case CBNode::kNodeData: {
const CBData* node = node_->as<CBData>();
ASMJIT_PROPAGATE(sb.appendFormat(".embed (%u bytes)", node->getSize()));
break;
}
case CBNode::kNodeAlign: {
const CBAlign* node = node_->as<CBAlign>();
ASMJIT_PROPAGATE(
sb.appendFormat(".align %u (%s)",
node->getAlignment(),
node->getMode() == kAlignCode ? "code" : "data"));
break;
}
case CBNode::kNodeComment: {
const CBComment* node = node_->as<CBComment>();
ASMJIT_PROPAGATE(sb.appendFormat("; %s", node->getInlineComment()));
break;
}
case CBNode::kNodeSentinel: {
ASMJIT_PROPAGATE(sb.appendString("[sentinel]"));
break;
}
#if !defined(ASMJIT_DISABLE_COMPILER)
case CBNode::kNodeFunc: {
const CCFunc* node = node_->as<CCFunc>();
ASMJIT_PROPAGATE(formatLabel(sb, logOptions, cb, node->getId()));
ASMJIT_PROPAGATE(sb.appendString(": ["));
ASMJIT_PROPAGATE(formatFuncRets(sb, logOptions, cb, node->getDetail(), nullptr));
ASMJIT_PROPAGATE(sb.appendString("]"));
ASMJIT_PROPAGATE(sb.appendString("("));
ASMJIT_PROPAGATE(formatFuncArgs(sb, logOptions, cb, node->getDetail(), node->getArgs()));
ASMJIT_PROPAGATE(sb.appendString(")"));
break;
}
case CBNode::kNodeFuncExit: {
ASMJIT_PROPAGATE(sb.appendString("[ret]"));
break;
}
case CBNode::kNodeFuncCall: {
const CCFuncCall* node = node_->as<CCFuncCall>();
ASMJIT_PROPAGATE(
Logging::formatInstruction(sb, logOptions, cb,
cb->getArchType(),
node->getInstDetail(), node->getOpArray(), node->getOpCount()));
break;
}
#endif // !ASMJIT_DISABLE_COMPILER
default: {
ASMJIT_PROPAGATE(sb.appendFormat("[unknown (type=%u)]", node_->getType()));
break;
}
}
return kErrorOk;
}
#endif // !ASMJIT_DISABLE_BUILDER
Error Logging::formatLine(StringBuilder& sb, const uint8_t* binData, size_t binLen, size_t dispLen, size_t imLen, const char* comment) noexcept {
size_t currentLen = sb.getLength();
size_t commentLen = comment ? Utils::strLen(comment, kMaxCommentLength) : 0;
ASMJIT_ASSERT(binLen >= dispLen);
if ((binLen != 0 && binLen != Globals::kInvalidIndex) || commentLen) {
size_t align = kMaxInstLength;
char sep = ';';
for (size_t i = (binLen == Globals::kInvalidIndex); i < 2; i++) {
size_t begin = sb.getLength();
// Append align.
if (currentLen < align)
ASMJIT_PROPAGATE(sb.appendChars(' ', align - currentLen));
// Append separator.
if (sep) {
ASMJIT_PROPAGATE(sb.appendChar(sep));
ASMJIT_PROPAGATE(sb.appendChar(' '));
}
// Append binary data or comment.
if (i == 0) {
ASMJIT_PROPAGATE(sb.appendHex(binData, binLen - dispLen - imLen));
ASMJIT_PROPAGATE(sb.appendChars('.', dispLen * 2));
ASMJIT_PROPAGATE(sb.appendHex(binData + binLen - imLen, imLen));
if (commentLen == 0) break;
}
else {
ASMJIT_PROPAGATE(sb.appendString(comment, commentLen));
}
currentLen += sb.getLength() - begin;
align += kMaxBinaryLength;
sep = '|';
}
}
return sb.appendChar('\n');
}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_LOGGING

View File

@ -1,288 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_LOGGING_H
#define _ASMJIT_BASE_LOGGING_H
// [Dependencies]
#include "../base/inst.h"
#include "../base/string.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base
//! \{
#if !defined(ASMJIT_DISABLE_LOGGING)
// ============================================================================
// [Forward Declarations]
// ============================================================================
class CodeEmitter;
class Reg;
struct Operand_;
#if !defined(ASMJIT_DISABLE_BUILDER)
class CodeBuilder;
class CBNode;
#endif // !ASMJIT_DISABLE_BUILDER
// ============================================================================
// [asmjit::Logger]
// ============================================================================
//! Abstract logging interface and helpers.
//!
//! This class can be inherited and reimplemented to fit into your logging
//! subsystem. When reimplementing use `Logger::_log()` method to log into
//! a custom stream.
//!
//! There are two \ref Logger implementations offered by AsmJit:
//! - \ref FileLogger - allows to log into a `FILE*` stream.
//! - \ref StringLogger - logs into a \ref StringBuilder.
class ASMJIT_VIRTAPI Logger {
public:
ASMJIT_NONCOPYABLE(Logger)
// --------------------------------------------------------------------------
// [Options]
// --------------------------------------------------------------------------
//! Logger options.
ASMJIT_ENUM(Options) {
kOptionBinaryForm = 0x00000001, //! Output instructions also in binary form.
kOptionImmExtended = 0x00000002, //! Output a meaning of some immediates.
kOptionHexImmediate = 0x00000004, //! Output constants in hexadecimal form.
kOptionHexDisplacement = 0x00000008 //! Output displacements in hexadecimal form.
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a `Logger` instance.
ASMJIT_API Logger() noexcept;
//! Destroy the `Logger` instance.
ASMJIT_API virtual ~Logger() noexcept;
// --------------------------------------------------------------------------
// [Logging]
// --------------------------------------------------------------------------
//! Log `str` - must be reimplemented.
virtual Error _log(const char* str, size_t len) noexcept = 0;
//! Log a string `str`, which is either null terminated or having `len` length.
ASMJIT_INLINE Error log(const char* str, size_t len = Globals::kInvalidIndex) noexcept { return _log(str, len); }
//! Log a content of a `StringBuilder` `str`.
ASMJIT_INLINE Error log(const StringBuilder& str) noexcept { return _log(str.getData(), str.getLength()); }
//! Format the message by using `sprintf()` and then send to `log()`.
ASMJIT_API Error logf(const char* fmt, ...) noexcept;
//! Format the message by using `vsprintf()` and then send to `log()`.
ASMJIT_API Error logv(const char* fmt, va_list ap) noexcept;
//! Log binary data.
ASMJIT_API Error logBinary(const void* data, size_t size) noexcept;
// --------------------------------------------------------------------------
// [Options]
// --------------------------------------------------------------------------
//! Get all logger options as a single integer.
ASMJIT_INLINE uint32_t getOptions() const noexcept { return _options; }
//! Get the given logger option.
ASMJIT_INLINE bool hasOption(uint32_t option) const noexcept { return (_options & option) != 0; }
ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _options |= options; }
ASMJIT_INLINE void clearOptions(uint32_t options) noexcept { _options &= ~options; }
// --------------------------------------------------------------------------
// [Indentation]
// --------------------------------------------------------------------------
//! Get indentation.
ASMJIT_INLINE const char* getIndentation() const noexcept { return _indentation; }
//! Set indentation.
ASMJIT_API void setIndentation(const char* indentation) noexcept;
//! Reset indentation.
ASMJIT_INLINE void resetIndentation() noexcept { setIndentation(nullptr); }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Options, see \ref LoggerOption.
uint32_t _options;
//! Indentation.
char _indentation[12];
};
// ============================================================================
// [asmjit::FileLogger]
// ============================================================================
//! Logger that can log to a `FILE*` stream.
class ASMJIT_VIRTAPI FileLogger : public Logger {
public:
ASMJIT_NONCOPYABLE(FileLogger)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `FileLogger` that logs to a `FILE` stream.
ASMJIT_API FileLogger(FILE* stream = nullptr) noexcept;
//! Destroy the `FileLogger`.
ASMJIT_API virtual ~FileLogger() noexcept;
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the logging out put stream or null.
ASMJIT_INLINE FILE* getStream() const noexcept { return _stream; }
//! Set the logging output stream to `stream` or null.
//!
//! NOTE: If the `stream` is null it will disable logging, but it won't
//! stop calling `log()` unless the logger is detached from the
//! \ref Assembler.
ASMJIT_INLINE void setStream(FILE* stream) noexcept { _stream = stream; }
// --------------------------------------------------------------------------
// [Logging]
// --------------------------------------------------------------------------
ASMJIT_API Error _log(const char* buf, size_t len = Globals::kInvalidIndex) noexcept override;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! C file stream.
FILE* _stream;
};
// ============================================================================
// [asmjit::StringLogger]
// ============================================================================
//! Logger that stores everything in an internal string buffer.
class ASMJIT_VIRTAPI StringLogger : public Logger {
public:
ASMJIT_NONCOPYABLE(StringLogger)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create new `StringLogger`.
ASMJIT_API StringLogger() noexcept;
//! Destroy the `StringLogger`.
ASMJIT_API virtual ~StringLogger() noexcept;
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get `char*` pointer which represents the resulting string.
//!
//! The pointer is owned by `StringLogger`, it can't be modified or freed.
ASMJIT_INLINE const char* getString() const noexcept { return _stringBuilder.getData(); }
//! Clear the resulting string.
ASMJIT_INLINE void clearString() noexcept { _stringBuilder.clear(); }
//! Get the length of the string returned by `getString()`.
ASMJIT_INLINE size_t getLength() const noexcept { return _stringBuilder.getLength(); }
// --------------------------------------------------------------------------
// [Logging]
// --------------------------------------------------------------------------
ASMJIT_API Error _log(const char* buf, size_t len = Globals::kInvalidIndex) noexcept override;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Output string.
StringBuilder _stringBuilder;
};
// ============================================================================
// [asmjit::Logging]
// ============================================================================
struct Logging {
ASMJIT_API static Error formatRegister(
StringBuilder& sb,
uint32_t logOptions,
const CodeEmitter* emitter,
uint32_t archType,
uint32_t regType,
uint32_t regId) noexcept;
ASMJIT_API static Error formatLabel(
StringBuilder& sb,
uint32_t logOptions,
const CodeEmitter* emitter,
uint32_t labelId) noexcept;
ASMJIT_API static Error formatOperand(
StringBuilder& sb,
uint32_t logOptions,
const CodeEmitter* emitter,
uint32_t archType,
const Operand_& op) noexcept;
ASMJIT_API static Error formatInstruction(
StringBuilder& sb,
uint32_t logOptions,
const CodeEmitter* emitter,
uint32_t archType,
const Inst::Detail& detail, const Operand_* opArray, uint32_t opCount) noexcept;
#if !defined(ASMJIT_DISABLE_BUILDER)
ASMJIT_API static Error formatNode(
StringBuilder& sb,
uint32_t logOptions,
const CodeBuilder* cb,
const CBNode* node_) noexcept;
#endif // !ASMJIT_DISABLE_BUILDER
// Only used by AsmJit internals, not available to users.
#if defined(ASMJIT_EXPORTS)
enum {
// Has to be big to be able to hold all metadata compiler can assign to a
// single instruction.
kMaxCommentLength = 512,
kMaxInstLength = 40,
kMaxBinaryLength = 26
};
static Error formatLine(
StringBuilder& sb,
const uint8_t* binData, size_t binLen, size_t dispLen, size_t imLen, const char* comment) noexcept;
#endif // ASMJIT_EXPORTS
};
#else
class Logger;
#endif // !ASMJIT_DISABLE_LOGGING
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_LOGGER_H

View File

@ -1,74 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_MISC_P_H
#define _ASMJIT_BASE_MISC_P_H
// [Dependencies]
#include "../asmjit_build.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base
//! \{
//! \internal
//!
//! Macro used to populate a table with 16 elements starting at `I`.
#define ASMJIT_TABLE_16(DEF, I) DEF(I + 0), DEF(I + 1), DEF(I + 2), DEF(I + 3), \
DEF(I + 4), DEF(I + 5), DEF(I + 6), DEF(I + 7), \
DEF(I + 8), DEF(I + 9), DEF(I + 10), DEF(I + 11), \
DEF(I + 12), DEF(I + 13), DEF(I + 14), DEF(I + 15)
#define ASMJIT_TABLE_T_8(TABLE, VALUE, I) \
TABLE< I + 0 >::VALUE, TABLE< I + 1 >::VALUE, \
TABLE< I + 2 >::VALUE, TABLE< I + 3 >::VALUE, \
TABLE< I + 4 >::VALUE, TABLE< I + 5 >::VALUE, \
TABLE< I + 6 >::VALUE, TABLE< I + 7 >::VALUE
#define ASMJIT_TABLE_T_16(TABLE, VALUE, I) \
ASMJIT_TABLE_T_8(TABLE, VALUE, I), \
ASMJIT_TABLE_T_8(TABLE, VALUE, I + 8)
#define ASMJIT_TABLE_T_32(TABLE, VALUE, I) \
ASMJIT_TABLE_T_16(TABLE, VALUE, I), \
ASMJIT_TABLE_T_16(TABLE, VALUE, I + 16)
#define ASMJIT_TABLE_T_64(TABLE, VALUE, I) \
ASMJIT_TABLE_T_32(TABLE, VALUE, I), \
ASMJIT_TABLE_T_32(TABLE, VALUE, I + 32)
#define ASMJIT_TABLE_T_128(TABLE, VALUE, I) \
ASMJIT_TABLE_T_64(TABLE, VALUE, I), \
ASMJIT_TABLE_T_64(TABLE, VALUE, I + 64)
#define ASMJIT_TABLE_T_256(TABLE, VALUE, I) \
ASMJIT_TABLE_T_128(TABLE, VALUE, I), \
ASMJIT_TABLE_T_128(TABLE, VALUE, I + 128)
#define ASMJIT_TABLE_T_512(TABLE, VALUE, I) \
ASMJIT_TABLE_T_256(TABLE, VALUE, I), \
ASMJIT_TABLE_T_256(TABLE, VALUE, I + 256)
#define ASMJIT_TABLE_T_1024(TABLE, VALUE, I) \
ASMJIT_TABLE_T_512(TABLE, VALUE, I), \
ASMJIT_TABLE_T_512(TABLE, VALUE, I + 512)
//! \}
} // asmjit namespace
//! \}
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_MISC_P_H

View File

@ -1,209 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies]
#include "../base/operand.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::TypeId]
// ============================================================================
template<int ID>
struct TypeIdSizeOf_T {
enum {
kValue = (ID == TypeId::kI8 ) ? 1 :
(ID == TypeId::kU8 ) ? 1 :
(ID == TypeId::kI16 ) ? 2 :
(ID == TypeId::kU16 ) ? 2 :
(ID == TypeId::kI32 ) ? 4 :
(ID == TypeId::kU32 ) ? 4 :
(ID == TypeId::kI64 ) ? 8 :
(ID == TypeId::kU64 ) ? 8 :
(ID == TypeId::kF32 ) ? 4 :
(ID == TypeId::kF64 ) ? 8 :
(ID == TypeId::kF80 ) ? 10 :
(ID == TypeId::kMask8 ) ? 1 :
(ID == TypeId::kMask16) ? 2 :
(ID == TypeId::kMask32) ? 4 :
(ID == TypeId::kMask64) ? 8 :
(ID == TypeId::kMmx32 ) ? 4 :
(ID == TypeId::kMmx64 ) ? 8 :
(ID >= TypeId::_kVec32Start && ID <= TypeId::_kVec32End ) ? 4 :
(ID >= TypeId::_kVec64Start && ID <= TypeId::_kVec64End ) ? 8 :
(ID >= TypeId::_kVec128Start && ID <= TypeId::_kVec128End) ? 16 :
(ID >= TypeId::_kVec256Start && ID <= TypeId::_kVec256End) ? 32 :
(ID >= TypeId::_kVec512Start && ID <= TypeId::_kVec512End) ? 64 : 0
};
};
template<int ID>
struct TypeIdElementOf_T {
enum {
kValue = (ID == TypeId::kMask8 ) ? TypeId::kU8 :
(ID == TypeId::kMask16) ? TypeId::kU16 :
(ID == TypeId::kMask32) ? TypeId::kU32 :
(ID == TypeId::kMask64) ? TypeId::kU64 :
(ID == TypeId::kMmx32 ) ? TypeId::kI32 :
(ID == TypeId::kMmx64 ) ? TypeId::kI64 :
(ID >= TypeId::kI8 && ID <= TypeId::kF80 ) ? ID :
(ID >= TypeId::_kVec32Start && ID <= TypeId::_kVec32End ) ? ID - TypeId::_kVec32Start + TypeId::kI8 :
(ID >= TypeId::_kVec64Start && ID <= TypeId::_kVec64End ) ? ID - TypeId::_kVec64Start + TypeId::kI8 :
(ID >= TypeId::_kVec128Start && ID <= TypeId::_kVec128End) ? ID - TypeId::_kVec128Start + TypeId::kI8 :
(ID >= TypeId::_kVec256Start && ID <= TypeId::_kVec256End) ? ID - TypeId::_kVec256Start + TypeId::kI8 :
(ID >= TypeId::_kVec512Start && ID <= TypeId::_kVec512End) ? ID - TypeId::_kVec512Start + TypeId::kI8 : 0
};
};
#define R(TMPL, I) TMPL<I + 0>::kValue, TMPL<I + 1>::kValue, \
TMPL<I + 2>::kValue, TMPL<I + 3>::kValue, \
TMPL<I + 4>::kValue, TMPL<I + 5>::kValue, \
TMPL<I + 6>::kValue, TMPL<I + 7>::kValue, \
TMPL<I + 8>::kValue, TMPL<I + 9>::kValue, \
TMPL<I + 10>::kValue, TMPL<I + 11>::kValue, \
TMPL<I + 12>::kValue, TMPL<I + 13>::kValue, \
TMPL<I + 14>::kValue, TMPL<I + 15>::kValue
ASMJIT_API const TypeId::Info TypeId::_info = {
// SizeOf[128]
{
R(TypeIdSizeOf_T, 0), R(TypeIdSizeOf_T, 16),
R(TypeIdSizeOf_T, 32), R(TypeIdSizeOf_T, 48),
R(TypeIdSizeOf_T, 64), R(TypeIdSizeOf_T, 80),
R(TypeIdSizeOf_T, 96), R(TypeIdSizeOf_T, 112)
},
// ElementOf[128]
{
R(TypeIdElementOf_T, 0), R(TypeIdElementOf_T, 16),
R(TypeIdElementOf_T, 32), R(TypeIdElementOf_T, 48),
R(TypeIdElementOf_T, 64), R(TypeIdElementOf_T, 80),
R(TypeIdElementOf_T, 96), R(TypeIdElementOf_T, 112)
}
};
#undef R
// ============================================================================
// [asmjit::Operand - Test]
// ============================================================================
#if defined(ASMJIT_TEST)
UNIT(base_operand) {
INFO("Checking operand sizes");
EXPECT(sizeof(Operand) == 16);
EXPECT(sizeof(Reg) == 16);
EXPECT(sizeof(Mem) == 16);
EXPECT(sizeof(Imm) == 16);
EXPECT(sizeof(Label) == 16);
INFO("Checking basic functionality of Operand");
Operand a, b;
Operand dummy;
EXPECT(a.isNone() == true);
EXPECT(a.isReg() == false);
EXPECT(a.isMem() == false);
EXPECT(a.isImm() == false);
EXPECT(a.isLabel() == false);
EXPECT(a == b);
EXPECT(a._any.reserved8_4 == 0, "Default constructed Operand should zero its 'reserved8_4' field");
EXPECT(a._any.reserved12_4 == 0, "Default constructed Operand should zero its 'reserved12_4' field");
INFO("Checking basic functionality of Label");
Label label;
EXPECT(label.isValid() == false);
EXPECT(label.getId() == 0);
INFO("Checking basic functionality of Reg");
EXPECT(Reg().isValid() == false,
"Default constructed Reg() should not be valid");
EXPECT(Reg()._any.reserved8_4 == 0,
"A default constructed Reg() should zero its 'reserved8_4' field");
EXPECT(Reg()._any.reserved12_4 == 0,
"A default constructed Reg() should zero its 'reserved12_4' field");
EXPECT(Reg().isReg() == false,
"Default constructed register should not isReg()");
EXPECT(dummy.as<Reg>().isValid() == false,
"Default constructed Operand casted to Reg should not be valid");
// Create some register (not specific to any architecture).
uint32_t rSig = Operand::kOpReg | (1 << Operand::kSignatureRegTypeShift) |
(2 << Operand::kSignatureRegKindShift) |
(8 << Operand::kSignatureSizeShift ) ;
Reg r1(Reg::fromSignature(rSig, 5));
EXPECT(r1.isValid() == true);
EXPECT(r1.isReg() == true);
EXPECT(r1.isReg(1) == true);
EXPECT(r1.isPhysReg() == true);
EXPECT(r1.isVirtReg() == false);
EXPECT(r1.getSignature() == rSig);
EXPECT(r1.getType() == 1);
EXPECT(r1.getKind() == 2);
EXPECT(r1.getSize() == 8);
EXPECT(r1.getId() == 5);
EXPECT(r1.isReg(1, 5) == true); // RegType and Id.
EXPECT(r1._any.reserved8_4 == 0, "Reg should have 'reserved8_4' zero");
EXPECT(r1._any.reserved12_4 == 0, "Reg should have 'reserved12_4' zero");
// The same type of register having different id.
Reg r2(r1, 6);
EXPECT(r2.isValid() == true);
EXPECT(r2.isReg() == true);
EXPECT(r2.isReg(1) == true);
EXPECT(r2.isPhysReg() == true);
EXPECT(r2.isVirtReg() == false);
EXPECT(r2.getSignature() == rSig);
EXPECT(r2.getType() == r1.getType());
EXPECT(r2.getKind() == r1.getKind());
EXPECT(r2.getSize() == r1.getSize());
EXPECT(r2.getId() == 6);
EXPECT(r2.isReg(1, 6) == true);
r1.reset();
EXPECT(!r1.isValid(),
"Reset register should not be valid");
EXPECT(!r1.isReg(),
"Reset register should not isReg()");
INFO("Checking basic functionality of Mem");
Mem m;
EXPECT(m.isMem() , "Default constructed Mem() should isMem()");
EXPECT(m == Mem() , "Two default constructed Mem() operands should be equal");
EXPECT(m.hasBase() == false , "Default constructed Mem() should not have base specified");
EXPECT(m.hasIndex() == false , "Default constructed Mem() should not have index specified");
EXPECT(m.has64BitOffset() == true , "Default constructed Mem() should report 64-bit offset");
EXPECT(m.getOffset() == 0 , "Default constructed Mem() should have be zero offset / address");
m.setOffset(-1);
EXPECT(m.getOffsetLo32() == -1 , "Memory operand must hold a 32-bit offset");
EXPECT(m.getOffset() == -1 , "32-bit offset must be sign extended to 64 bits");
int64_t x = int64_t(ASMJIT_UINT64_C(0xFF00FF0000000001));
m.setOffset(x);
EXPECT(m.getOffset() == x , "Memory operand must hold a 64-bit offset");
EXPECT(m.getOffsetLo32() == 1 , "Memory operand must return correct low offset DWORD");
EXPECT(m.getOffsetHi32() == 0xFF00FF00, "Memory operand must return correct high offset DWORD");
INFO("Checking basic functionality of Imm");
EXPECT(Imm(-1).getInt64() == int64_t(-1),
"Immediate values should by default sign-extend to 64-bits");
}
#endif // ASMJIT_TEST
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"

View File

@ -1,228 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies]
#include "../base/osutils.h"
#include "../base/utils.h"
#if ASMJIT_OS_POSIX
# include <sys/types.h>
# include <sys/mman.h>
# include <time.h>
# include <unistd.h>
#endif // ASMJIT_OS_POSIX
#if ASMJIT_OS_MAC
# include <mach/mach_time.h>
#endif // ASMJIT_OS_MAC
#if ASMJIT_OS_WINDOWS
# if defined(_MSC_VER) && _MSC_VER >= 1400
# include <intrin.h>
# else
# define _InterlockedCompareExchange InterlockedCompareExchange
# endif // _MSC_VER
#endif // ASMJIT_OS_WINDOWS
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::OSUtils - Virtual Memory]
// ============================================================================
// Windows specific implementation using `VirtualAllocEx` and `VirtualFree`.
#if ASMJIT_OS_WINDOWS
static ASMJIT_NOINLINE const VMemInfo& OSUtils_GetVMemInfo() noexcept {
static VMemInfo vmi;
if (ASMJIT_UNLIKELY(!vmi.hCurrentProcess)) {
SYSTEM_INFO info;
::GetSystemInfo(&info);
vmi.pageSize = Utils::alignToPowerOf2<uint32_t>(info.dwPageSize);
vmi.pageGranularity = info.dwAllocationGranularity;
vmi.hCurrentProcess = ::GetCurrentProcess();
}
return vmi;
};
VMemInfo OSUtils::getVirtualMemoryInfo() noexcept { return OSUtils_GetVMemInfo(); }
void* OSUtils::allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept {
return allocProcessMemory(static_cast<HANDLE>(0), size, allocated, flags);
}
Error OSUtils::releaseVirtualMemory(void* p, size_t size) noexcept {
return releaseProcessMemory(static_cast<HANDLE>(0), p, size);
}
void* OSUtils::allocProcessMemory(HANDLE hProcess, size_t size, size_t* allocated, uint32_t flags) noexcept {
if (size == 0)
return nullptr;
const VMemInfo& vmi = OSUtils_GetVMemInfo();
if (!hProcess) hProcess = vmi.hCurrentProcess;
// VirtualAllocEx rounds the allocated size to a page size automatically,
// but we need the `alignedSize` so we can store the real allocated size
// into `allocated` output.
size_t alignedSize = Utils::alignTo(size, vmi.pageSize);
// Windows XP SP2 / Vista+ allow data-execution-prevention (DEP).
DWORD protectFlags = 0;
if (flags & kVMExecutable)
protectFlags |= (flags & kVMWritable) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
else
protectFlags |= (flags & kVMWritable) ? PAGE_READWRITE : PAGE_READONLY;
LPVOID mBase = ::VirtualAllocEx(hProcess, nullptr, alignedSize, MEM_COMMIT | MEM_RESERVE, protectFlags);
if (ASMJIT_UNLIKELY(!mBase)) return nullptr;
ASMJIT_ASSERT(Utils::isAligned<size_t>(reinterpret_cast<size_t>(mBase), vmi.pageSize));
if (allocated) *allocated = alignedSize;
return mBase;
}
Error OSUtils::releaseProcessMemory(HANDLE hProcess, void* p, size_t size) noexcept {
const VMemInfo& vmi = OSUtils_GetVMemInfo();
if (!hProcess) hProcess = vmi.hCurrentProcess;
if (ASMJIT_UNLIKELY(!::VirtualFreeEx(hProcess, p, 0, MEM_RELEASE)))
return DebugUtils::errored(kErrorInvalidState);
return kErrorOk;
}
#endif // ASMJIT_OS_WINDOWS
// Posix specific implementation using `mmap()` and `munmap()`.
#if ASMJIT_OS_POSIX
// Mac uses MAP_ANON instead of MAP_ANONYMOUS.
#if !defined(MAP_ANONYMOUS)
# define MAP_ANONYMOUS MAP_ANON
#endif // MAP_ANONYMOUS
static const VMemInfo& OSUtils_GetVMemInfo() noexcept {
static VMemInfo vmi;
if (ASMJIT_UNLIKELY(!vmi.pageSize)) {
size_t pageSize = ::getpagesize();
vmi.pageSize = pageSize;
vmi.pageGranularity = std::max<size_t>(pageSize, 65536);
}
return vmi;
};
VMemInfo OSUtils::getVirtualMemoryInfo() noexcept { return OSUtils_GetVMemInfo(); }
void* OSUtils::allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept {
const VMemInfo& vmi = OSUtils_GetVMemInfo();
size_t alignedSize = Utils::alignTo<size_t>(size, vmi.pageSize);
int protection = PROT_READ;
if (flags & kVMWritable ) protection |= PROT_WRITE;
if (flags & kVMExecutable) protection |= PROT_EXEC;
void* mbase = ::mmap(nullptr, alignedSize, protection, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (ASMJIT_UNLIKELY(mbase == MAP_FAILED)) return nullptr;
if (allocated) *allocated = alignedSize;
return mbase;
}
Error OSUtils::releaseVirtualMemory(void* p, size_t size) noexcept {
if (ASMJIT_UNLIKELY(::munmap(p, size) != 0))
return DebugUtils::errored(kErrorInvalidState);
return kErrorOk;
}
#endif // ASMJIT_OS_POSIX
// ============================================================================
// [asmjit::OSUtils - GetTickCount]
// ============================================================================
#if ASMJIT_OS_WINDOWS
static ASMJIT_INLINE uint32_t OSUtils_calcHiRes(const LARGE_INTEGER& now, double freq) noexcept {
return static_cast<uint32_t>(
(int64_t)(double(now.QuadPart) / freq) & 0xFFFFFFFF);
}
uint32_t OSUtils::getTickCount() noexcept {
static volatile uint32_t _hiResTicks;
static volatile double _hiResFreq;
do {
uint32_t hiResOk = _hiResTicks;
LARGE_INTEGER qpf, now;
// If for whatever reason this fails, bail to `GetTickCount()`.
if (!::QueryPerformanceCounter(&now)) break;
// Expected - if we ran through this at least once `hiResTicks` will be
// either 1 or 0xFFFFFFFF. If it's '1' then the Hi-Res counter is available
// and `QueryPerformanceCounter()` can be used.
if (hiResOk == 1) return OSUtils_calcHiRes(now, _hiResFreq);
// Hi-Res counter is not available, bail to `GetTickCount()`.
if (hiResOk != 0) break;
// Detect availability of Hi-Res counter, if not available, bail to `GetTickCount()`.
if (!::QueryPerformanceFrequency(&qpf)) {
_InterlockedCompareExchange((LONG*)&_hiResTicks, 0xFFFFFFFF, 0);
break;
}
double freq = double(qpf.QuadPart) / 1000.0;
_hiResFreq = freq;
_InterlockedCompareExchange((LONG*)&_hiResTicks, 1, 0);
return OSUtils_calcHiRes(now, freq);
} while (0);
return ::GetTickCount();
}
#elif ASMJIT_OS_MAC
uint32_t OSUtils::getTickCount() noexcept {
static mach_timebase_info_data_t _machTime;
// See Apple's QA1398.
if (ASMJIT_UNLIKELY(_machTime.denom == 0) || mach_timebase_info(&_machTime) != KERN_SUCCESS)
return 0;
// `mach_absolute_time()` returns nanoseconds, we want milliseconds.
uint64_t t = mach_absolute_time() / 1000000;
t = t * _machTime.numer / _machTime.denom;
return static_cast<uint32_t>(t & 0xFFFFFFFFU);
}
#elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
uint32_t OSUtils::getTickCount() noexcept {
struct timespec ts;
if (ASMJIT_UNLIKELY(clock_gettime(CLOCK_MONOTONIC, &ts) != 0))
return 0;
uint64_t t = (uint64_t(ts.tv_sec ) * 1000) + (uint64_t(ts.tv_nsec) / 1000000);
return static_cast<uint32_t>(t & 0xFFFFFFFFU);
}
#else
#error "[asmjit] OSUtils::getTickCount() is not implemented for your target OS."
uint32_t OSUtils::getTickCount() noexcept { return 0; }
#endif
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"

Some files were not shown because too many files have changed in this diff Show More