yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
c39c29bf4
master
1// slang-artifact-desc-util.cpp 2#include "slang-artifact-desc-util.h" 3 4#include "../core/slang-io.h" 5#include "../core/slang-type-text-util.h" 6#include "slang-artifact-impl.h" 7#include "slang-artifact-representation.h" 8 9namespace Slang 10{ 11 12namespace 13{// anonymous 14 15struct HierarchicalEnumEntry 16{ 17Index value ; 18Index parent ; 19const char * name ; 20}; 21 22static bool _isHierarchicalEnumOk (ConstArrayView < HierarchicalEnumEntry > entries ,Count countOf ) 23{ 24// All values should be set 25if (entries .getCount ()!= countOf ) 26 { 27return false; 28 } 29 30List < uint8_t > isUsed ; 31isUsed .setCount (countOf ); 32 ::memset (isUsed .getBuffer (),0 ,countOf ); 33 34for (const auto & entry :entries ) 35 { 36const auto value = entry .value ; 37// Must be in range 38if (value < 0 || value >=countOf ) 39 { 40return false; 41 } 42 43if (isUsed [value ]!= 0 ) 44 { 45return false; 46 } 47// Mark as used 48isUsed [value ]++ ; 49 } 50 51// There can't be any gaps 52for (auto v :isUsed ) 53 { 54if (v == 0 ) 55 { 56return false; 57 } 58 } 59 60// Okay, looks reasonable.. 61return true; 62} 63 64template < typename T > 65struct HierarchicalEnumTable 66{ 67HierarchicalEnumTable (ConstArrayView < HierarchicalEnumEntry > entries ) 68 { 69// Remove warnings around this not being used. 70 { 71const auto unused = _isHierarchicalEnumOk ; 72SLANG_UNUSED (unused ); 73 } 74 75SLANG_COMPILE_TIME_ASSERT (Index (T ::Invalid )< Index (T ::Base )); 76SLANG_ASSERT (entries .getCount ()== Count (T ::CountOf )); 77 78SLANG_ASSERT (_isHierarchicalEnumOk (entries ,Count (T ::CountOf ))); 79 80 ::memset (& m_parents ,0 ,sizeof (m_parents )); 81 82for (const auto & entry :entries ) 83 { 84const auto value = entry .value ; 85m_parents [value ]= T (entry .parent ); 86m_names [value ]= UnownedStringSlice (entry .name ); 87 } 88 89// TODO(JS): NOTE! If we wanted to use parent to indicate if a value was *invalid* 90// we would want the Parent of Base to be Base. 91// 92// Base parent should be invalid 93SLANG_ASSERT (getParent (T ::Base )== T ::Invalid ); 94// Invalids parent should be invalid 95SLANG_ASSERT (getParent (T ::Invalid )== T ::Invalid ); 96 } 97 98T getParent (T kind )const {return (kind >=T ::CountOf ) ?T ::Invalid :m_parents [Index (kind )]; } 99UnownedStringSlice getName (T kind )const 100 { 101return (kind >=T ::CountOf ) ?UnownedStringSlice () :m_names [Index (kind )]; 102 } 103 104bool isDerivedFrom (T type ,T base )const 105 { 106if (Index (type ) >=Index (T ::CountOf )) 107 { 108return false; 109 } 110 111do 112 { 113if (type == base ) 114 { 115return true; 116 } 117type = m_parents [Index (type )]; 118 }while (Index (type ) >=Index (T ::Base )); 119 120return false; 121 } 122 123protected : 124T m_parents [Count (T ::CountOf )]; 125UnownedStringSlice m_names [Count (T ::CountOf )]; 126}; 127 128}// namespace 129 130// Macro utils to create "enum hierarchy" tables 131 132#define SLANG_HIERARCHICAL_ENUM_GET_VALUES (ENUM_TYPE ,ENUM_TYPE_MACRO ,ENUM_ENTRY_MACRO ) \ 133 static ConstArrayView<HierarchicalEnumEntry> _getEntries##ENUM_TYPE() \ 134 { \ 135 static const HierarchicalEnumEntry values[] = {ENUM_TYPE_MACRO(ENUM_ENTRY_MACRO)}; \ 136 return makeConstArrayView(values); \ 137 } 138 139#define SLANG_HIERARCHICAL_ENUM (ENUM_TYPE ,ENUM_TYPE_MACRO ,ENUM_VALUE_MACRO ) \ 140 SLANG_HIERARCHICAL_ENUM_GET_VALUES(ENUM_TYPE, ENUM_TYPE_MACRO, ENUM_VALUE_MACRO) \ 141 \ 142 static const HierarchicalEnumTable<ENUM_TYPE> g_table##ENUM_TYPE(_getEntries##ENUM_TYPE()); \ 143 \ 144 ENUM_TYPE getParent(ENUM_TYPE kind) \ 145 { \ 146 return g_table##ENUM_TYPE.getParent(kind); \ 147 } \ 148 UnownedStringSlice getName(ENUM_TYPE kind) \ 149 { \ 150 return g_table##ENUM_TYPE.getName(kind); \ 151 } \ 152 bool isDerivedFrom(ENUM_TYPE kind, ENUM_TYPE base) \ 153 { \ 154 return g_table##ENUM_TYPE.isDerivedFrom(kind, base); \ 155 } 156 157/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactKind !!!!!!!!!!!!!!!!!!!!!!! */ 158 159// clang-format off 160#define SLANG_ARTIFACT_KIND (x ) \ 161 x(Invalid, Invalid) \ 162 x(Base, Invalid) \ 163 x(None, Base) \ 164 x(Unknown, Base) \ 165 x(BinaryFormat, Base) \ 166 x(Container, BinaryFormat) \ 167 x(Zip, Container) \ 168 x(RiffContainer, Container) \ 169 x(RiffLz4Container, Container) \ 170 x(RiffDeflateContainer, Container) \ 171 x(CompileBinary, BinaryFormat) \ 172 x(ObjectCode, CompileBinary) \ 173 x(Library, CompileBinary) \ 174 x(Executable, CompileBinary) \ 175 x(SharedLibrary, CompileBinary) \ 176 x(HostCallable, CompileBinary) \ 177 x(Text, Base) \ 178 x(HumanText, Text) \ 179 x(Source, Text) \ 180 x(Assembly, Text) \ 181 x(Json, Text) \ 182 x(Instance, Base) 183 184#define SLANG_ARTIFACT_KIND_ENTRY (TYPE ,PARENT ) { Index(ArtifactKind::TYPE), Index(ArtifactKind::PARENT), #TYPE }, 185 186SLANG_HIERARCHICAL_ENUM (ArtifactKind ,SLANG_ARTIFACT_KIND ,SLANG_ARTIFACT_KIND_ENTRY ) 187 188/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactPayload !!!!!!!!!!!!!!!!!!!!!!! */ 189 190#define SLANG_ARTIFACT_PAYLOAD (x ) \ 191 x(Invalid, Invalid) \ 192 x(Base, Invalid) \ 193 x(None, Base) \ 194 x(Unknown, Base) \ 195 x(Source, Base) \ 196 x(C, Source) \ 197 x(Cpp, Source) \ 198 x(HLSL, Source) \ 199 x(GLSL, Source) \ 200 x(CUDA, Source) \ 201 x(Metal, Source) \ 202 x(Slang, Source) \ 203 x(WGSL, Source) \ 204 x(KernelLike, Base) \ 205 x(DXIL, KernelLike) \ 206 x(DXBC, KernelLike) \ 207 x(SPIRV, KernelLike) \ 208 x(PTX, KernelLike) \ 209 x(CuBin, KernelLike) \ 210 x(MetalAIR, KernelLike) \ 211 x(WGSL_SPIRV, KernelLike) \ 212 x(CPULike, Base) \ 213 x(UnknownCPU, CPULike) \ 214 x(X86, CPULike) \ 215 x(X86_64, CPULike) \ 216 x(Aarch, CPULike) \ 217 x(Aarch64, CPULike) \ 218 x(HostCPU, CPULike) \ 219 x(UniversalCPU, CPULike) \ 220 x(GeneralIR, Base) \ 221 x(SlangIR, GeneralIR) \ 222 x(LLVMIR, GeneralIR) \ 223 x(AST, Base) \ 224 x(SlangAST, AST) \ 225 x(CompileResults, Base) \ 226 x(Metadata, Base) \ 227 x(DebugInfo, Metadata) \ 228 x(PdbDebugInfo, DebugInfo) \ 229 x(Diagnostics, Metadata) \ 230 x(PostEmitMetadata, Metadata) \ 231 x(Miscellaneous, Base) \ 232 x(Log, Miscellaneous) \ 233 x(Lock, Miscellaneous) \ 234 x(SourceMap, Base) 235 236#define SLANG_ARTIFACT_PAYLOAD_ENTRY (TYPE ,PARENT ) { Index(ArtifactPayload::TYPE), Index(ArtifactPayload::PARENT), #TYPE }, 237 238SLANG_HIERARCHICAL_ENUM (ArtifactPayload ,SLANG_ARTIFACT_PAYLOAD ,SLANG_ARTIFACT_PAYLOAD_ENTRY ) 239 240/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactStyle !!!!!!!!!!!!!!!!!!!!!!! */ 241 242#define SLANG_ARTIFACT_STYLE (x ) \ 243 x(Invalid, Invalid) \ 244 x(Base, Invalid) \ 245 x(None, Base) \ 246 x(Unknown, Base) \ 247 x(CodeLike, Base) \ 248 x(Kernel, CodeLike) \ 249 x(Host, CodeLike) \ 250 x(Obfuscated, Base) 251// clang-format on 252 253#define SLANG_ARTIFACT_STYLE_ENTRY (TYPE ,PARENT ) \ 254 {Index(ArtifactStyle::TYPE), Index(ArtifactStyle::PARENT), #TYPE}, 255 256SLANG_HIERARCHICAL_ENUM (ArtifactStyle ,SLANG_ARTIFACT_STYLE ,SLANG_ARTIFACT_STYLE_ENTRY ) 257 258/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ArtifactDescUtil !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */ 259 260/* static */ ArtifactDesc ArtifactDescUtil ::makeDescForCompileTarget (SlangCompileTarget target ) 261{ 262switch (target ) 263 { 264case SLANG_TARGET_UNKNOWN : 265return Desc ::make (Kind ::Unknown ,Payload ::None ,Style ::Unknown ,0 ); 266case SLANG_TARGET_NONE : 267return Desc ::make (Kind ::None ,Payload ::None ,Style ::Unknown ,0 ); 268case SLANG_GLSL : 269 { 270// For the moment we Desc::make all just map to GLSL, but we could use flags 271// or some other mechanism to distinguish the types 272return Desc ::make (Kind ::Source ,Payload ::GLSL ,Style ::Kernel ,0 ); 273 } 274case SLANG_HLSL : 275return Desc ::make (Kind ::Source ,Payload ::HLSL ,Style ::Kernel ,0 ); 276case SLANG_SPIRV : 277return Desc ::make (Kind ::ObjectCode ,Payload ::SPIRV ,Style ::Kernel ,0 ); 278case SLANG_SPIRV_ASM : 279return Desc ::make (Kind ::Assembly ,Payload ::SPIRV ,Style ::Kernel ,0 ); 280case SLANG_DXBC : 281return Desc ::make (Kind ::ObjectCode ,Payload ::DXBC ,Style ::Kernel ,0 ); 282case SLANG_DXBC_ASM : 283return Desc ::make (Kind ::Assembly ,Payload ::DXBC ,Style ::Kernel ,0 ); 284case SLANG_DXIL : 285return Desc ::make (Kind ::ObjectCode ,Payload ::DXIL ,Style ::Kernel ,0 ); 286case SLANG_DXIL_ASM : 287return Desc ::make (Kind ::Assembly ,Payload ::DXIL ,Style ::Kernel ,0 ); 288case SLANG_C_SOURCE : 289return Desc ::make (Kind ::Source ,Payload ::C ,Style ::Kernel ,0 ); 290case SLANG_CPP_SOURCE : 291return Desc ::make (Kind ::Source ,Payload ::Cpp ,Style ::Kernel ,0 ); 292case SLANG_HOST_CPP_SOURCE : 293return Desc ::make (Kind ::Source ,Payload ::Cpp ,Style ::Host ,0 ); 294case SLANG_CPP_PYTORCH_BINDING : 295return Desc ::make (Kind ::Source ,Payload ::Cpp ,Style ::Host ,0 ); 296case SLANG_HOST_EXECUTABLE : 297return Desc ::make (Kind ::Executable ,Payload ::HostCPU ,Style ::Host ,0 ); 298case SLANG_HOST_SHARED_LIBRARY : 299return Desc ::make (Kind ::SharedLibrary ,Payload ::HostCPU ,Style ::Host ,0 ); 300case SLANG_SHADER_SHARED_LIBRARY : 301return Desc ::make (Kind ::SharedLibrary ,Payload ::HostCPU ,Style ::Kernel ,0 ); 302case SLANG_SHADER_HOST_CALLABLE : 303return Desc ::make (Kind ::HostCallable ,Payload ::HostCPU ,Style ::Kernel ,0 ); 304case SLANG_CUDA_SOURCE : 305return Desc ::make (Kind ::Source ,Payload ::CUDA ,Style ::Kernel ,0 ); 306// TODO(JS): 307// Not entirely clear how best to represent PTX here. We could mark as 'Assembly'. 308// Saying it is 'Executable' implies it is Binary (which PTX isn't). Executable also 309// implies 'complete for executation', irrespective of it being text. 310case SLANG_PTX : 311return Desc ::make (Kind ::ObjectCode ,Payload ::PTX ,Style ::Kernel ,0 ); 312case SLANG_OBJECT_CODE : 313return Desc ::make (Kind ::ObjectCode ,Payload ::HostCPU ,Style ::Kernel ,0 ); 314case SLANG_HOST_HOST_CALLABLE : 315return Desc ::make (Kind ::HostCallable ,Payload ::HostCPU ,Style ::Host ,0 ); 316case SLANG_METAL : 317return Desc ::make (Kind ::Source ,Payload ::Metal ,Style ::Kernel ,0 ); 318case SLANG_METAL_LIB : 319return Desc ::make (Kind ::ObjectCode ,Payload ::MetalAIR ,Style ::Kernel ,0 ); 320case SLANG_METAL_LIB_ASM : 321return Desc ::make (Kind ::Assembly ,Payload ::MetalAIR ,Style ::Kernel ,0 ); 322case SLANG_WGSL : 323return Desc ::make (Kind ::Source ,Payload ::WGSL ,Style ::Kernel ,0 ); 324case SLANG_WGSL_SPIRV_ASM : 325return Desc ::make (Kind ::Assembly ,Payload ::WGSL_SPIRV ,Style ::Kernel ,0 ); 326case SLANG_WGSL_SPIRV : 327return Desc ::make (Kind ::ObjectCode ,Payload ::WGSL_SPIRV ,Style ::Kernel ,0 ); 328 329case SLANG_HOST_VM : 330return Desc ::make (Kind ::ObjectCode ,Payload ::UniversalCPU ,Style ::Host ,0 ); 331default : 332break ; 333 } 334 335SLANG_UNEXPECTED ("Unhandled type" ); 336} 337 338 339/* static */ ArtifactPayload ArtifactDescUtil ::getPayloadForSourceLanaguage ( 340SlangSourceLanguage language ) 341{ 342switch (language ) 343 { 344default : 345case SLANG_SOURCE_LANGUAGE_UNKNOWN : 346return Payload ::Unknown ; 347case SLANG_SOURCE_LANGUAGE_SLANG : 348return Payload ::Slang ; 349case SLANG_SOURCE_LANGUAGE_HLSL : 350return Payload ::HLSL ; 351case SLANG_SOURCE_LANGUAGE_GLSL : 352return Payload ::GLSL ; 353case SLANG_SOURCE_LANGUAGE_C : 354return Payload ::C ; 355case SLANG_SOURCE_LANGUAGE_CPP : 356return Payload ::Cpp ; 357case SLANG_SOURCE_LANGUAGE_CUDA : 358return Payload ::CUDA ; 359 } 360} 361 362/* static */ ArtifactDesc ArtifactDescUtil ::makeDescForSourceLanguage (SlangSourceLanguage language ) 363{ 364return Desc ::make (Kind ::Source ,getPayloadForSourceLanaguage (language ),Style ::Unknown ,0 ); 365} 366 367/* static */ SlangCompileTarget ArtifactDescUtil ::getCompileTargetFromDesc (const ArtifactDesc & desc ) 368{ 369switch (desc .kind ) 370 { 371case ArtifactKind ::None : 372return SLANG_TARGET_NONE ; 373case ArtifactKind ::Source : 374 { 375switch (desc .payload ) 376 { 377case Payload ::HLSL : 378return SLANG_HLSL ; 379case Payload ::GLSL : 380return SLANG_GLSL ; 381case Payload ::C : 382return SLANG_C_SOURCE ; 383case Payload ::Cpp : 384return (desc .style == Style ::Host ) ?SLANG_HOST_CPP_SOURCE :SLANG_CPP_SOURCE ; 385case Payload ::CUDA : 386return SLANG_CUDA_SOURCE ; 387case Payload ::Metal : 388return SLANG_METAL ; 389case Payload ::WGSL : 390return SLANG_WGSL ; 391default : 392break ; 393 } 394break ; 395 } 396case ArtifactKind ::Assembly : 397 { 398switch (desc .payload ) 399 { 400case Payload ::SPIRV : 401return SLANG_SPIRV_ASM ; 402case Payload ::DXIL : 403return SLANG_DXIL_ASM ; 404case Payload ::DXBC : 405return SLANG_DXBC_ASM ; 406case Payload ::PTX : 407return SLANG_PTX ; 408case Payload ::MetalAIR : 409return SLANG_METAL_LIB_ASM ; 410case Payload ::WGSL_SPIRV : 411return SLANG_WGSL_SPIRV_ASM ; 412default : 413break ; 414 } 415 } 416default : 417break ; 418 } 419 420if (isDerivedFrom (desc .kind ,ArtifactKind ::CompileBinary )) 421 { 422if (isDerivedFrom (desc .payload ,ArtifactPayload ::CPULike )) 423 { 424switch (desc .kind ) 425 { 426case Kind ::Executable : 427return SLANG_HOST_EXECUTABLE ; 428case Kind ::SharedLibrary : 429return desc .style == ArtifactStyle ::Host ?SLANG_HOST_SHARED_LIBRARY 430 :SLANG_SHADER_SHARED_LIBRARY ; 431case Kind ::HostCallable : 432return desc .style == ArtifactStyle ::Host ?SLANG_HOST_HOST_CALLABLE 433 :SLANG_SHADER_HOST_CALLABLE ; 434case Kind ::ObjectCode : 435return SLANG_OBJECT_CODE ; 436default : 437break ; 438 } 439 } 440else 441 { 442switch (desc .payload ) 443 { 444case Payload ::SPIRV : 445return SLANG_SPIRV ; 446case Payload ::DXIL : 447return SLANG_DXIL ; 448case Payload ::DXBC : 449return SLANG_DXBC ; 450case Payload ::PTX : 451return SLANG_PTX ; 452case Payload ::MetalAIR : 453return SLANG_METAL_LIB_ASM ; 454case Payload ::WGSL_SPIRV : 455return SLANG_WGSL_SPIRV ; 456default : 457break ; 458 } 459 } 460 } 461 462return SLANG_TARGET_UNKNOWN ; 463} 464 465 466namespace 467{// anonymous 468struct KindExtension 469{ 470ArtifactKind kind ; 471UnownedStringSlice ext ; 472}; 473}// namespace 474 475#define SLANG_KIND_EXTENSION (kind ,ext ) {ArtifactKind::kind, toSlice(ext)}, 476 477static const KindExtension g_cpuKindExts []= { 478#if SLANG_WINDOWS_FAMILY 479SLANG_KIND_EXTENSION (Library ,"lib" )SLANG_KIND_EXTENSION (ObjectCode ,"obj" ) 480SLANG_KIND_EXTENSION (Executable ,"exe" )SLANG_KIND_EXTENSION (SharedLibrary ,"dll" ) 481#else 482SLANG_KIND_EXTENSION (Library ,"a" )SLANG_KIND_EXTENSION (ObjectCode ,"o" ) 483SLANG_KIND_EXTENSION (Executable ,"" ) 484 485#if __CYGWIN__ 486SLANG_KIND_EXTENSION (SharedLibrary ,"dll" ) 487#elif SLANG_APPLE_FAMILY 488SLANG_KIND_EXTENSION (SharedLibrary ,"dylib" ) 489#else 490SLANG_KIND_EXTENSION (SharedLibrary ,"so" ) 491#endif 492 493#endif 494}; 495 496/* static */ bool ArtifactDescUtil ::isCpuBinary (const ArtifactDesc & desc ) 497{ 498return isDerivedFrom (desc .kind ,ArtifactKind ::CompileBinary )&& 499isDerivedFrom (desc .payload ,ArtifactPayload ::CPULike ); 500} 501 502/* static */ bool ArtifactDescUtil ::isText (const ArtifactDesc & desc ) 503{ 504// If it's derived from text... 505if (isDerivedFrom (desc .kind ,ArtifactKind ::Text )) 506 { 507return true; 508 } 509 510// Special case PTX... 511if (isDerivedFrom (desc .kind ,ArtifactKind ::CompileBinary )) 512 { 513return desc .payload == ArtifactPayload ::PTX ; 514 } 515 516// Not text 517return false; 518} 519 520/* static */ bool ArtifactDescUtil ::isGpuUsable (const ArtifactDesc & desc ) 521{ 522if (isDerivedFrom (desc .kind ,ArtifactKind ::CompileBinary )) 523 { 524return isDerivedFrom (desc .payload ,ArtifactPayload ::KernelLike ); 525 } 526 527// PTX is a kind of special case, it's an 'assembly' (low level text represention) that can be 528// passed to CUDA runtime 529return desc .kind == ArtifactKind ::Assembly && desc .payload == ArtifactPayload ::PTX ; 530} 531 532/* static */ bool ArtifactDescUtil ::isKindBinaryLinkable (Kind kind ) 533{ 534switch (kind ) 535 { 536case Kind ::Library : 537case Kind ::ObjectCode : 538 { 539return true; 540 } 541default : 542break ; 543 } 544return false; 545} 546 547/* static */ bool ArtifactDescUtil ::isLinkable (const ArtifactDesc & desc ) 548{ 549// If is a container with compile results *assume* that result is linkable 550if (isDerivedFrom (desc .kind ,ArtifactKind ::Container )&& 551isDerivedFrom (desc .payload ,ArtifactPayload ::CompileResults )) 552 { 553return true; 554 } 555 556// if it's a compile binary or a container 557if (isDerivedFrom (desc .kind ,ArtifactKind ::CompileBinary )) 558 { 559if (isDerivedFrom (desc .payload ,ArtifactPayload ::KernelLike )) 560 { 561// It seems as if DXBC is potentially linkable from 562// https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-appendix-keywords#export 563 564// We can't *actually* link PTX or SPIR-V currently but it is in principal possible 565// so let's say we accept for now 566 567return true; 568 } 569else if (isDerivedFrom (desc .payload ,ArtifactPayload ::CPULike )) 570 { 571// If kind is exe or shared library, linking will arguably not work 572if (desc .kind == ArtifactKind ::SharedLibrary || desc .kind == ArtifactKind ::Executable ) 573 { 574return false; 575 } 576 577return true; 578 } 579else if (isDerivedFrom (desc .payload ,ArtifactPayload ::GeneralIR )) 580 { 581// We'll *assume* IR is linkable 582return true; 583 } 584 } 585return false; 586} 587 588/* static */ bool ArtifactDescUtil ::isCpuLikeTarget (const ArtifactDesc & desc ) 589{ 590if (isDerivedFrom (desc .kind ,ArtifactKind ::CompileBinary )) 591 { 592return isDerivedFrom (desc .payload ,ArtifactPayload ::CPULike ); 593 } 594else if (isDerivedFrom (desc .kind ,ArtifactKind ::Source )) 595 { 596// We'll assume C/C++ are targetting CPU, although that is perhaps somewhat arguable. 597return desc .payload == Payload ::C || desc .payload == Payload ::Cpp ; 598 } 599 600return false; 601} 602 603/* static */ ArtifactDesc ArtifactDescUtil ::getDescFromExtension (const UnownedStringSlice & slice ) 604{ 605if (slice == "slang-module" || slice == "slang-lib" ) 606 { 607return ArtifactDesc ::make (ArtifactKind ::Library ,ArtifactPayload ::SlangIR ); 608 } 609 610// Metal 611// https://developer.apple.com/documentation/metal/shader_libraries/building_a_library_with_metal_s_command-line_tools 612if (slice == toSlice ("air" )) 613 { 614return ArtifactDesc ::make (ArtifactKind ::ObjectCode ,ArtifactPayload ::MetalAIR ); 615 } 616else if (slice == toSlice ("metallib" )|| slice == toSlice ("metalar" )) 617 { 618return ArtifactDesc ::make (ArtifactKind ::Library ,ArtifactPayload ::MetalAIR ); 619 } 620 621if (slice == toSlice ("zip" )) 622 { 623return ArtifactDesc ::make (ArtifactKind ::Zip ,ArtifactPayload ::Unknown ); 624 } 625 626if (slice .startsWith (toSlice ("riff" ))) 627 { 628auto tail = slice .tail (4 ); 629if (tail .getLength ()== 0 ) 630 { 631return ArtifactDesc ::make (ArtifactKind ::RiffContainer ,ArtifactPayload ::Unknown ); 632 } 633else if (tail == "-lz4" ) 634 { 635return ArtifactDesc ::make (ArtifactKind ::RiffLz4Container ,ArtifactPayload ::Unknown ); 636 } 637else if (tail == "-deflate" ) 638 { 639return ArtifactDesc ::make (ArtifactKind ::RiffDeflateContainer ,ArtifactPayload ::Unknown ); 640 } 641 } 642 643if (slice == toSlice ("asm" )) 644 { 645// We'll assume asm means current CPU assembler.. 646return ArtifactDesc ::make (ArtifactKind ::Assembly ,ArtifactPayload ::HostCPU ); 647 } 648 649// TODO(JS): Unfortunately map extension is also used from output for linkage from 650// Visual Studio. It's used here for source map. 651if (slice == toSlice ("map" )) 652 { 653return ArtifactDesc ::make (ArtifactKind ::Json ,ArtifactPayload ::SourceMap ); 654 } 655 656if (slice == toSlice ("pdb" )) 657 { 658// Program database 659return ArtifactDesc ::make (ArtifactKind ::Assembly ,ArtifactPayload ::PdbDebugInfo ); 660 } 661 662for (const auto & kindExt :g_cpuKindExts ) 663 { 664if (slice == kindExt .ext ) 665 { 666// We'll assume it's for the host CPU for now.. 667return ArtifactDesc ::make (kindExt .kind ,Payload ::HostCPU ); 668 } 669 } 670 671const auto target = TypeTextUtil ::findCompileTargetFromExtension (slice ); 672 673return makeDescForCompileTarget (target ); 674} 675 676/* static */ ArtifactDesc ArtifactDescUtil ::getDescFromPath (const UnownedStringSlice & slice ) 677{ 678auto extension = Path ::getPathExt (slice ); 679return getDescFromExtension (extension ); 680} 681 682/* static*/ SlangResult ArtifactDescUtil ::appendCpuExtensionForKind (Kind kind ,StringBuilder & out ) 683{ 684for (const auto & kindExt :g_cpuKindExts ) 685 { 686if (kind == kindExt .kind ) 687 { 688out <<kindExt .ext ; 689return SLANG_OK ; 690 } 691 } 692return SLANG_E_NOT_FOUND ; 693} 694 695static UnownedStringSlice _getPayloadExtension (ArtifactPayload payload ) 696{ 697typedef ArtifactPayload Payload ; 698switch (payload ) 699 { 700/* Source types */ 701case Payload ::HLSL : 702return toSlice ("hlsl" ); 703case Payload ::GLSL : 704return toSlice ("glsl" ); 705 706case Payload ::Cpp : 707return toSlice ("cpp" ); 708case Payload ::C : 709return toSlice ("c" ); 710 711case Payload ::Metal : 712return toSlice ("metal" ); 713 714case Payload ::CUDA : 715return toSlice ("cu" ); 716 717case Payload ::Slang : 718return toSlice ("slang" ); 719 720/* Binary types */ 721case Payload ::DXIL : 722return toSlice ("dxil" ); 723case Payload ::DXBC : 724return toSlice ("dxbc" ); 725case Payload ::SPIRV : 726return toSlice ("spv" ); 727 728case Payload ::PTX : 729return toSlice ("ptx" ); 730 731case Payload ::LLVMIR : 732return toSlice ("llvm-ir" ); 733 734case Payload ::SlangIR : 735return toSlice ("slang-ir" ); 736 737case Payload ::MetalAIR : 738return toSlice ("metallib" ); 739 740case Payload ::PdbDebugInfo : 741return toSlice ("pdb" ); 742case Payload ::SourceMap : 743return toSlice ("map" ); 744 745default : 746break ; 747 } 748return UnownedStringSlice (); 749} 750 751SlangResult ArtifactDescUtil ::appendDefaultExtension (const ArtifactDesc & desc ,StringBuilder & out ) 752{ 753switch (desc .kind ) 754 { 755case ArtifactKind ::Library : 756 { 757// Special cases 758if (desc .payload == Payload ::SlangIR ) 759 { 760out <<toSlice ("slang-module" ); 761return SLANG_OK ; 762 } 763else if (desc .payload == Payload ::MetalAIR ) 764 { 765// https://developer.apple.com/documentation/metal/shader_libraries/building_a_library_with_metal_s_command-line_tools 766out <<toSlice ("metallib" ); 767return SLANG_OK ; 768 } 769 770break ; 771 } 772case ArtifactKind ::Zip : 773 { 774out <<toSlice ("zip" ); 775return SLANG_OK ; 776 } 777case ArtifactKind ::RiffContainer : 778 { 779out <<toSlice ("riff" ); 780return SLANG_OK ; 781 } 782case ArtifactKind ::RiffLz4Container : 783 { 784out <<toSlice ("riff-lz4" ); 785return SLANG_OK ; 786 } 787case ArtifactKind ::RiffDeflateContainer : 788 { 789out <<toSlice ("riff-deflate" ); 790return SLANG_OK ; 791 } 792case ArtifactKind ::Assembly : 793 { 794// Special case PTX, because it is assembly 795if (desc .payload == Payload ::PTX ) 796 { 797out <<_getPayloadExtension (desc .payload ); 798return SLANG_OK ; 799 } 800 801// We'll just use asm for all CPU assembly type 802if (isDerivedFrom (desc .payload ,ArtifactPayload ::CPULike )) 803 { 804out <<toSlice ("asm" ); 805return SLANG_OK ; 806 } 807 808// Use the payload extension "-asm" 809out <<_getPayloadExtension (desc .payload ); 810out <<toSlice ("-asm" ); 811return SLANG_OK ; 812 } 813case ArtifactKind ::Source : 814 { 815auto ext = _getPayloadExtension (desc .payload ); 816if (ext .begin ()!= nullptr ) 817 { 818out <<ext ; 819return SLANG_OK ; 820 } 821// Don't know the extension for that 822return SLANG_E_NOT_FOUND ; 823 } 824case ArtifactKind ::Json : 825 { 826auto ext = _getPayloadExtension (desc .payload ); 827if (ext .begin ()!= nullptr ) 828 { 829// TODO(JS): 830// Do we need to alter the extension or the name if it's an 831// obfuscated map? 832// if (isDerivedFrom(desc.style, ArtifactStyle::Obfuscated)) 833//{ 834//} 835 836out <<ext ; 837return SLANG_OK ; 838 } 839 840// Not really what kind of json, so just use 'generic' json extension 841out <<"json" ; 842return SLANG_OK ; 843 } 844case ArtifactKind ::CompileBinary : 845 { 846if (isDerivedFrom (desc .payload ,ArtifactPayload ::SlangIR )|| 847isDerivedFrom (desc .payload ,ArtifactPayload ::SlangAST )) 848 { 849out <<"slang-module" ; 850return SLANG_OK ; 851 } 852break ; 853 } 854default : 855break ; 856 } 857 858if (ArtifactDescUtil ::isGpuUsable (desc )) 859 { 860auto ext = _getPayloadExtension (desc .payload ); 861if (ext .getLength ()) 862 { 863out <<ext ; 864return SLANG_OK ; 865 } 866 } 867 868if (ArtifactDescUtil ::isCpuLikeTarget (desc )&& 869 !isDerivedFrom (desc .payload ,ArtifactPayload ::Source )) 870 { 871return appendCpuExtensionForKind (desc .kind ,out ); 872 } 873 874return SLANG_E_NOT_FOUND ; 875} 876 877/* static */ String ArtifactDescUtil ::getBaseNameFromPath ( 878const ArtifactDesc & desc , 879const UnownedStringSlice & path ) 880{ 881const String name = Path ::getFileName (path ); 882return getBaseNameFromName (desc ,name .getUnownedSlice ()); 883} 884 885/* static */ String ArtifactDescUtil ::getBaseNameFromName ( 886const ArtifactDesc & desc , 887const UnownedStringSlice & inName ) 888{ 889String name (inName ); 890 891const bool isSharedLibraryPrefixPlatform = SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY ; 892if (isSharedLibraryPrefixPlatform ) 893 { 894// Strip lib prefix 895if (isCpuBinary (desc )&& 896 (desc .kind == ArtifactKind ::Library || desc .kind == ArtifactKind ::SharedLibrary )) 897 { 898// If it starts with lib strip it 899if (name .startsWith ("lib" )) 900 { 901const String stripLib = name .getUnownedSlice ().tail (3 ); 902name = stripLib ; 903 } 904 } 905 } 906 907// Strip any extension 908 { 909StringBuilder descExt ; 910if (SLANG_SUCCEEDED (appendDefaultExtension (desc ,descExt ))&& descExt .getLength ()) 911 { 912// TODO(JS): 913// It has an extension. We could check if they are the same 914// but if they are not that might be fine, because of case insensitivity 915// or perhaps there are multiple valid extensions. So for now we just strip 916// and don't bother confirming with something like.. 917// if (Path::getPathExt(name) == descExt)) 918 919name = Path ::getFileNameWithoutExt (name ); 920 } 921 } 922 923return name ; 924} 925 926/* static */ String ArtifactDescUtil ::getBaseName ( 927const ArtifactDesc & desc , 928IPathArtifactRepresentation * pathRep ) 929{ 930UnownedStringSlice path (pathRep -> getPath ()); 931return getBaseNameFromPath (desc ,path ); 932} 933 934/* static */ SlangResult ArtifactDescUtil ::hasDefinedNameForDesc (const ArtifactDesc & desc ) 935{ 936StringBuilder buf ; 937return SLANG_SUCCEEDED (appendDefaultExtension (desc ,buf )); 938} 939 940/* static */ SlangResult ArtifactDescUtil ::calcNameForDesc ( 941const ArtifactDesc & desc , 942const UnownedStringSlice & inBaseName , 943StringBuilder & outName ) 944{ 945UnownedStringSlice baseName (inBaseName ); 946 947// If there is no basename, set one 948if (baseName .getLength ()== 0 ) 949 { 950baseName = toSlice ("unknown" ); 951 } 952 953// Prefix 954if (isCpuBinary (desc )&& 955 (desc .kind == ArtifactKind ::SharedLibrary || desc .kind == ArtifactKind ::Library )) 956 { 957const bool isSharedLibraryPrefixPlatform = SLANG_LINUX_FAMILY || SLANG_APPLE_FAMILY ; 958if (isSharedLibraryPrefixPlatform ) 959 { 960outName <<"lib" ; 961 } 962 } 963 964// Output the basename 965outName <<baseName ; 966 967// If there is an extension append it 968StringBuilder ext ; 969if (SLANG_SUCCEEDED (appendDefaultExtension (desc ,ext ))) 970 { 971if (ext .getLength ()) 972 { 973outName .appendChar ('.' ); 974outName .append (ext ); 975 } 976 } 977else 978 { 979// If we can't determine the type we can output with .unknown 980outName .append (toSlice (".unknown" )); 981 } 982 983return SLANG_OK ; 984} 985 986/* static */ SlangResult ArtifactDescUtil ::calcPathForDesc ( 987const ArtifactDesc & desc , 988const UnownedStringSlice & basePath , 989StringBuilder & outPath ) 990{ 991outPath .clear (); 992 993// Append the directory 994Index pos = Path ::findLastSeparatorIndex (basePath ); 995if (pos >=0 ) 996 { 997// Keep the stem including the delimiter 998outPath .append (basePath .head (pos + 1 )); 999 1000StringBuilder buf ; 1001const auto baseName = basePath .tail (pos + 1 ); 1002 1003SLANG_RETURN_ON_FAIL (calcNameForDesc (desc ,baseName ,buf )); 1004outPath .append (buf ); 1005 1006return SLANG_OK ; 1007 } 1008else 1009 { 1010return calcNameForDesc (desc ,basePath ,outPath ); 1011 } 1012} 1013 1014/* static */ bool ArtifactDescUtil ::isDisassembly (const ArtifactDesc & from ,const ArtifactDesc & to ) 1015{ 1016// From must be a binary like type 1017if (!isDerivedFrom (from .kind ,ArtifactKind ::CompileBinary )) 1018 { 1019return false; 1020 } 1021 1022 1023// Target must be assembly, and the payload be the same type 1024if (!(to .kind == ArtifactKind ::Assembly && to .payload == from .payload )) 1025 { 1026return false; 1027 } 1028 1029const auto payload = from .payload ; 1030 1031// Check the payload seems like something plausible to 'disassemble' 1032if (!(isDerivedFrom (payload ,ArtifactPayload ::KernelLike )|| 1033isDerivedFrom (payload ,ArtifactPayload ::CPULike )|| 1034isDerivedFrom (payload ,ArtifactPayload ::GeneralIR ))) 1035 { 1036return false; 1037 } 1038 1039// If the flags or style are different, then it's something more than just disassembly 1040if (!(from .style == to .style && from .flags == to .flags )) 1041 { 1042return false; 1043 } 1044 1045return true; 1046} 1047 1048/* static */ void ArtifactDescUtil ::appendText (const ArtifactDesc & desc ,StringBuilder & out ) 1049{ 1050out <<getName (desc .kind ) <<"/" <<getName (desc .payload ) <<"/" <<getName (desc .style ); 1051// TODO(JS): Output flags? None currently used 1052} 1053 1054/* static */ String ArtifactDescUtil ::getText (const ArtifactDesc & desc ) 1055{ 1056StringBuilder buf ; 1057appendText (desc ,buf ); 1058return buf ; 1059} 1060 1061}// namespace Slang