diff --git a/docs/TROUBLESHOOTING.md b/docs/TROUBLESHOOTING.md index c46d3f0..e538f7b 100644 --- a/docs/TROUBLESHOOTING.md +++ b/docs/TROUBLESHOOTING.md @@ -135,6 +135,7 @@ A separate multi-window path stopped the active async presenter when another dif - **OpenDirectory 32-bit ivar errors:** keep `TARGET_i386=OFF`; the supported client is x86-64. - **Undefined empty Objective-C collection symbols:** retain the patched macOS 10.15 Objective-C runtime code generation. - **LLVM branch opcode errors:** retain the Indium LLVM 22/23 compatibility patch; do not replace its branch handling with an unconditional version-specific opcode. +- **Every game shader fails to compile on LLVM 23** (r3dlog full of `Failed to compile shader`, then `Material Missing Pipeline` and a crash before the loading screen; `/tmp/metal-errors.log` shows `Unsupported LLVM value: <3 x float> zeroinitializer`): LLVM 23 represents vector splats as vector-typed `ConstantFP`/`ConstantInt`, which Iridium did not translate. Indium now splats them itself. Rebuild and reinstall the Metal/Indium pair ([setup](SETUP.md#metal-and-indium-overlays)). The offline check `python3 tools/build-riot-air-check.py --native` translates shader libraries without the game. - **Build process killed:** lower parallelism, for example `JOBS=2 ./scripts/build.sh` or `--parallel 1` for an incremental component build. - **Incremental helper cannot find `flags.make` or `link.txt`:** use Unix Makefiles, not Ninja. - **Prebuilt Swift file contains Git LFS pointer text:** install Git LFS and fetch the original upstream assets; pointer text is not a usable library. diff --git a/patches/metal--deps--indium.patch b/patches/metal--deps--indium.patch index 8f0081c..8f34335 100644 --- a/patches/metal--deps--indium.patch +++ b/patches/metal--deps--indium.patch @@ -4802,7 +4802,7 @@ index 1e3e971..4db87d4 100644 - DynamicVK::vkFreeCommandBuffers(_device->device(), _device->oneshotCommandPool(), 1, &cmdBuf); }; diff --git a/src/iridium/air.cpp b/src/iridium/air.cpp -index 21c501f..24423e3 100644 +index 21c501f..9f6663b 100644 --- a/src/iridium/air.cpp +++ b/src/iridium/air.cpp @@ -4,9 +4,46 @@ @@ -5008,7 +5008,7 @@ index 21c501f..24423e3 100644 } break; default: -@@ -162,14 +299,32 @@ static Iridium::SPIRV::ResultID llvmValueToResultID(Iridium::SPIRV::Builder& bui +@@ -162,14 +299,60 @@ static Iridium::SPIRV::ResultID llvmValueToResultID(Iridium::SPIRV::Builder& bui { ResultID maybe = builder.lookupResultID(reinterpret_cast(llvmValue)); if (maybe != ResultIDInvalid) { @@ -5017,6 +5017,34 @@ index 21c501f..24423e3 100644 } } ++ // LLVM 23 represents vector splats (e.g. `<3 x float> zeroinitializer`) as vector-typed ConstantInt/ConstantFP values ++ // rather than ConstantAggregateZero/ConstantDataVector. Declare the scalar and splat it into a composite. ++ if ((kind == LLVMConstantIntValueKind || kind == LLVMConstantFPValueKind) && typeKind == LLVMVectorTypeKind) { ++ auto elementType = DynamicLLVM::LLVMGetElementType(type); ++ auto elementKind = DynamicLLVM::LLVMGetTypeKind(elementType); ++ ResultID element = ResultIDInvalid; ++ if (kind == LLVMConstantIntValueKind) { ++ auto val = DynamicLLVM::LLVMConstIntGetZExtValue(llvmValue); ++ auto width = DynamicLLVM::LLVMGetIntTypeWidth(elementType); ++ element = width == 1 ? builder.declareConstantBool(val != 0) : ((width <= 32) ? builder.declareConstantScalar(val) : builder.declareConstantScalar(val)); ++ } else { ++ LLVMBool losesInfo = false; ++ auto val = DynamicLLVM::LLVMConstRealGetDouble(llvmValue, &losesInfo); ++ switch (elementKind) { ++ case LLVMFloatTypeKind: element = builder.declareConstantScalar(val); break; ++ case LLVMDoubleTypeKind: element = builder.declareConstantScalar(val); break; ++ case LLVMHalfTypeKind: { ++ Iridium::Float16 tmp = val; ++ element = builder.declareConstantScalar(&tmp); ++ } break; ++ default: ++ throw ImpossibleResultID("Unsupported LLVM value: " + describeLLVMValue(llvmValue)); ++ } ++ } ++ std::vector vals(DynamicLLVM::LLVMGetVectorSize(type), element); ++ return builder.declareConstantComposite(llvmTypeToSPIRVType(builder, type), vals); ++ } ++ switch (kind) { + case LLVMGlobalVariableValueKind: { + auto initializer = DynamicLLVM::LLVMGetInitializer(llvmValue); @@ -5041,7 +5069,7 @@ index 21c501f..24423e3 100644 // TODO: how to determine if it's signed or not? return (width <= 32) ? builder.declareConstantScalar(val) : builder.declareConstantScalar(val); } break; -@@ -191,13 +346,15 @@ static Iridium::SPIRV::ResultID llvmValueToResultID(Iridium::SPIRV::Builder& bui +@@ -191,13 +374,15 @@ static Iridium::SPIRV::ResultID llvmValueToResultID(Iridium::SPIRV::Builder& bui } break; default: @@ -5060,7 +5088,7 @@ index 21c501f..24423e3 100644 for (size_t i = 0; i < count; ++i) { auto constant = DynamicLLVM::LLVMGetOperand(llvmValue, i); -@@ -207,10 +364,11 @@ static Iridium::SPIRV::ResultID llvmValueToResultID(Iridium::SPIRV::Builder& bui +@@ -207,10 +392,11 @@ static Iridium::SPIRV::ResultID llvmValueToResultID(Iridium::SPIRV::Builder& bui return builder.declareConstantComposite(llvmTypeToSPIRVType(builder, type), vals); } break; @@ -5074,7 +5102,7 @@ index 21c501f..24423e3 100644 for (size_t i = 0; i < count; ++i) { auto constant = DynamicLLVM::LLVMGetElementAsConstant(llvmValue, i); -@@ -220,7 +378,8 @@ static Iridium::SPIRV::ResultID llvmValueToResultID(Iridium::SPIRV::Builder& bui +@@ -220,7 +406,8 @@ static Iridium::SPIRV::ResultID llvmValueToResultID(Iridium::SPIRV::Builder& bui return builder.declareConstantComposite(llvmTypeToSPIRVType(builder, type), vals); } break; @@ -5084,7 +5112,7 @@ index 21c501f..24423e3 100644 return builder.declareUndefinedValue(llvmTypeToSPIRVType(builder, type)); } break; -@@ -231,6 +390,21 @@ static Iridium::SPIRV::ResultID llvmValueToResultID(Iridium::SPIRV::Builder& bui +@@ -231,6 +418,21 @@ static Iridium::SPIRV::ResultID llvmValueToResultID(Iridium::SPIRV::Builder& bui case LLVMConstantExprValueKind: { switch (DynamicLLVM::LLVMGetConstOpcode(llvmValue)) { @@ -5106,7 +5134,7 @@ index 21c501f..24423e3 100644 case LLVMBitCast: { auto target = DynamicLLVM::LLVMGetOperand(llvmValue, 0); auto targetID = llvmValueToResultID(builder, target); -@@ -254,13 +428,315 @@ static Iridium::SPIRV::ResultID llvmValueToResultID(Iridium::SPIRV::Builder& bui +@@ -254,13 +456,315 @@ static Iridium::SPIRV::ResultID llvmValueToResultID(Iridium::SPIRV::Builder& bui } break; default: @@ -5139,7 +5167,7 @@ index 21c501f..24423e3 100644 +static bool airTypeTokenIsFloat(std::string_view token) { + if (token.empty()) { + return false; -+ } + } + if (token[0] == 'v') { + token.remove_prefix(1); + while (!token.empty() && token[0] >= '0' && token[0] <= '9') { @@ -5418,13 +5446,13 @@ index 21c501f..24423e3 100644 + return false; + } + return true; - } ++ } + + return false; }; void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& outputInfo) { -@@ -312,7 +788,7 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -312,7 +816,7 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output }); // declare the GLSL PerVertex structure @@ -5433,7 +5461,7 @@ index 21c501f..24423e3 100644 SPIRV::Type::Member { vec4Type, 0, -@@ -321,13 +797,21 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -321,13 +825,21 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output } }, // TODO: declare the rest of the structure @@ -5456,7 +5484,7 @@ index 21c501f..24423e3 100644 // declare the GLSL VertexIndex input variable vertexIndexVar = builder.addGlobalVariable(ptrIntType, SPIRV::StorageClass::Input); -@@ -425,7 +909,7 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -425,7 +937,7 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output // if the function returns a structure, we need to separate the components // into separate output variables. @@ -5465,7 +5493,7 @@ index 21c501f..24423e3 100644 auto funcRetType = DynamicLLVM::LLVMGetReturnType(llfuncType); std::vector funcParamTypes(DynamicLLVM::LLVMCountParamTypes(llfuncType)); DynamicLLVM::LLVMGetParamTypes(llfuncType, funcParamTypes.data()); -@@ -460,7 +944,7 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -460,7 +972,7 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output auto type = llvmTypeToSPIRVType(builder, DynamicLLVM::LLVMStructGetTypeAtIndex(funcRetType, i)); auto ptrType = builder.declareType(SPIRV::Type(SPIRV::Type::PointerTag {}, SPIRV::StorageClass::Output, type, 8)); auto var = builder.addGlobalVariable(ptrType, SPIRV::StorageClass::Output); @@ -5474,7 +5502,7 @@ index 21c501f..24423e3 100644 ++location; _outputValueIDs.push_back(var); builder.referenceGlobalVariable(var); -@@ -472,13 +956,60 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -472,13 +984,60 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output auto type = llvmTypeToSPIRVType(builder, funcRetType); auto ptrType = builder.declareType(SPIRV::Type(SPIRV::Type::PointerTag {}, SPIRV::StorageClass::Output, type, 8)); auto var = builder.addGlobalVariable(ptrType, SPIRV::StorageClass::Output); @@ -5536,7 +5564,7 @@ index 21c501f..24423e3 100644 // // analyze parameters and mark special values (like the vertex ID) -@@ -519,7 +1050,9 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -519,7 +1078,9 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output auto kind = llvmMDStringToStringView(parameterInfo[1]); if (kind == "air.buffer") { @@ -5547,7 +5575,7 @@ index 21c501f..24423e3 100644 auto addrPtrTypeInst = SPIRV::Type(SPIRV::Type::PointerTag {}, SPIRV::StorageClass::PhysicalStorageBuffer, type, 8); auto addrPtrType = builder.declareType(addrPtrTypeInst); bufferMembers.push_back(SPIRV::Type::Member { addrPtrType, 8 * bufferIndex, {} }); -@@ -575,7 +1108,21 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -575,7 +1136,21 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output _parameterIDs.push_back(load); builder.associateExistingResultID(load, llparamVal); builder.setResultType(load, intType); @@ -5570,7 +5598,7 @@ index 21c501f..24423e3 100644 // find the location index info size_t infoIdx = 0; for (; infoIdx < parameterInfo.size(); ++infoIdx) { -@@ -620,7 +1167,7 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -620,7 +1195,7 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output auto var = builder.addGlobalVariable(ptrType, SPIRV::StorageClass::Input); auto load = builder.encodeLoad(type, var); @@ -5579,7 +5607,7 @@ index 21c501f..24423e3 100644 ++paramLocation; builder.referenceGlobalVariable(var); -@@ -631,9 +1178,18 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -631,9 +1206,18 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output builder.setResultType(load, type); } else if (kind == "air.vertex_input") { auto type = llvmTypeToSPIRVType(builder, funcParamTypes[i]); @@ -5600,7 +5628,7 @@ index 21c501f..24423e3 100644 // find the location index info size_t infoIdx = 0; -@@ -761,14 +1317,19 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -761,14 +1345,19 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output realSampleType = fakeSampleType; } @@ -5628,7 +5656,7 @@ index 21c501f..24423e3 100644 auto imagePtrType = builder.declareType(SPIRV::Type(SPIRV::Type::PointerTag {}, SPIRV::StorageClass::UniformConstant, imageType, 8)); auto var = builder.addGlobalVariable(imagePtrType, SPIRV::StorageClass::UniformConstant); //auto load = builder.encodeLoad(imageType, var); -@@ -959,68 +1520,98 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -959,68 +1548,98 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output enum class CFGType { None = 0, Selection, @@ -5776,7 +5804,7 @@ index 21c501f..24423e3 100644 if (isFirst) { isFirst = false; -@@ -1030,16 +1621,54 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -1030,16 +1649,54 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output builder.insertLabel(builder.lookupResultID(reinterpret_cast(bb))); } @@ -5832,7 +5860,7 @@ index 21c501f..24423e3 100644 builder.associateExistingResultID(resID, reinterpret_cast(inst)); builder.setResultType(resID, type); -@@ -1048,6 +1677,18 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -1048,6 +1705,18 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output // TODO: look into using physical addressing instead of logical addressing, which should simplify the translation process // (since i *think* that's the same addressing mode used by Metal code) @@ -5851,7 +5879,7 @@ index 21c501f..24423e3 100644 case LLVMGetElementPtr: { auto base = DynamicLLVM::LLVMGetOperand(inst, 0); auto targetType = DynamicLLVM::LLVMTypeOf(inst); -@@ -1060,17 +1701,32 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -1060,17 +1729,32 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output indices.push_back(llvmValueToResultID(builder, llindex)); } @@ -5885,7 +5913,7 @@ index 21c501f..24423e3 100644 // strangely enough, SPIR-V provides no instruction that can do an initial pointer offset like LLVM's GEP does. // there's OpPtrAccessChain, which is tantalizingly named, but unfortunately that instruction doesn't work as expected // either. i've tried using the raw index (i.e. in element units) and the multiplied index (i.e. in bytes), but no dice. -@@ -1112,6 +1768,9 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -1112,6 +1796,9 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output op = access; } @@ -5895,7 +5923,7 @@ index 21c501f..24423e3 100644 auto resID = builder.encodeLoad(type, op, alignment); builder.associateExistingResultID(resID, reinterpret_cast(inst)); -@@ -1149,50 +1808,8 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -1149,50 +1836,8 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output auto arg = DynamicLLVM::LLVMGetOperand(inst, 0); resID = builder.encodeConvertUToF(type, llvmValueToResultID(builder, arg)); @@ -5948,7 +5976,7 @@ index 21c501f..24423e3 100644 auto arg = DynamicLLVM::LLVMGetOperand(inst, 0); resID = builder.encodeFConvert(type, llvmValueToResultID(builder, arg)); -@@ -1223,14 +1840,33 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -1223,14 +1868,33 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output auto operand2 = DynamicLLVM::LLVMGetOperand(inst, 1); resID = builder.encodeFMax(type, llvmValueToResultID(builder, operand1), llvmValueToResultID(builder, operand2)); @@ -5985,7 +6013,7 @@ index 21c501f..24423e3 100644 case LLVMFMul: case LLVMFDiv: case LLVMFAdd: -@@ -1365,28 +2001,81 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -1365,28 +2029,81 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output auto op1 = DynamicLLVM::LLVMGetOperand(inst, 0); auto op2 = DynamicLLVM::LLVMGetOperand(inst, 1); auto predicate = DynamicLLVM::LLVMGetFCmpPredicate(inst); @@ -6016,16 +6044,16 @@ index 21c501f..24423e3 100644 + default: + throw std::runtime_error("TODO: handle fcmp predicate: " + std::to_string(predicate)); + } ++ ++ auto resID = builder.encodeRawOp(spirvOpcode, type, { llvmValueToResultID(builder, op1), llvmValueToResultID(builder, op2) }); - case LLVMRealOLT: { - resID = builder.encodeFOrdLessThan(llvmValueToResultID(builder, op1), llvmValueToResultID(builder, op2)); - } break; -+ auto resID = builder.encodeRawOp(spirvOpcode, type, { llvmValueToResultID(builder, op1), llvmValueToResultID(builder, op2) }); - + builder.associateExistingResultID(resID, reinterpret_cast(inst)); + builder.setResultType(resID, type); + } break; -+ + + case LLVMICmp: { + auto op1 = DynamicLLVM::LLVMGetOperand(inst, 0); + auto op2 = DynamicLLVM::LLVMGetOperand(inst, 1); @@ -6051,11 +6079,10 @@ index 21c501f..24423e3 100644 + auto resID = builder.encodeRawOp(spirvOpcode, type, { llvmValueToResultID(builder, op1), llvmValueToResultID(builder, op2) }); + - builder.associateExistingResultID(resID, reinterpret_cast(inst)); - builder.setResultType(resID, type); - } break; - -- case LLVMBr: { ++ builder.associateExistingResultID(resID, reinterpret_cast(inst)); ++ builder.setResultType(resID, type); ++ } break; ++ + case LLVMSelect: { + auto type = llvmTypeToSPIRVType(builder, DynamicLLVM::LLVMTypeOf(inst)); + auto resID = builder.encodeRawOp(SPIRVOp::Select, type, { @@ -6064,10 +6091,11 @@ index 21c501f..24423e3 100644 + llvmValueToResultID(builder, DynamicLLVM::LLVMGetOperand(inst, 2)), + }); + -+ builder.associateExistingResultID(resID, reinterpret_cast(inst)); -+ builder.setResultType(resID, type); -+ } break; -+ + builder.associateExistingResultID(resID, reinterpret_cast(inst)); + builder.setResultType(resID, type); + } break; + +- case LLVMBr: { + IRIDIUM_BR_CASES: { + auto loop=cfgInfos.find(builder.lookupResultID(reinterpret_cast(bb))); + if(loop!=cfgInfos.end() && loop->second.type==CFGType::Loop){ @@ -6078,7 +6106,7 @@ index 21c501f..24423e3 100644 if (DynamicLLVM::LLVMIsConditional(inst)) { auto condition = DynamicLLVM::LLVMGetCondition(inst); auto trueLabel = DynamicLLVM::LLVMBasicBlockAsValue(DynamicLLVM::LLVMGetSuccessor(inst, 0)); -@@ -1422,25 +2111,38 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -1422,25 +2139,38 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output auto type = llvmTypeToSPIRVType(builder, lltype); std::vector> variablesAndBlocks; @@ -6120,7 +6148,7 @@ index 21c501f..24423e3 100644 // ensure the resulting pointer storage class is the same as the input pointer storage class auto typeInst = *builder.reverseLookupType(type); -@@ -1474,6 +2176,7 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output +@@ -1474,6 +2204,7 @@ void Iridium::AIR::Function::analyze(SPIRV::Builder& builder, OutputInfo& output } } diff --git a/tools/build-riot-indium-runtime.py b/tools/build-riot-indium-runtime.py index a170332..a115c2a 100644 --- a/tools/build-riot-indium-runtime.py +++ b/tools/build-riot-indium-runtime.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 """Build the paired Iridium shader translator and Indium runtime overrides.""" from pathlib import Path +import os import shlex import subprocess import sys @@ -17,7 +18,8 @@ for line in (folder / 'CMakeFiles/iridium.dir/flags.make').read_text().splitline key, value = line.split(' = ', 1) iridium_flags[key] = shlex.split(value) iridium_flags['CXX_INCLUDES'] = current_includes(iridium_flags['CXX_INCLUDES']) -if (pinned_llvm / 'lib/libLLVM-22.so').exists(): +# RIOT_IRIDIUM_SYSTEM_LLVM=1 ignores the pin and builds against the host LLVM, as a fresh checkout does. +if (pinned_llvm / 'lib/libLLVM-22.so').exists() and os.environ.get('RIOT_IRIDIUM_SYSTEM_LLVM') != '1': iridium_flags['CXX_INCLUDES'].insert(0, '-I' + str(pinned_llvm / 'include')) iridium_flags['CXX_DEFINES'] = [value for value in iridium_flags['CXX_DEFINES'] if not value.startswith('-DHOST_LLVM_LIBNAME=')] iridium_flags['CXX_DEFINES'].append('-DHOST_LLVM_LIBNAME="' + str(pinned_llvm / 'lib/libLLVM-22.so') + '"')