yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
00746bf09
master
1-- Helper function to flatten the instruction hierarchy 2local function flatten_instructions ( insts , prefix , result ) 3prefix =prefix or "" 4result =result or {} 5 6for _ , entry in ipairs ( insts ) do 7for name , data in pairs ( entry ) do 8local full_name =prefix == "" and name or ( prefix .. "." .. name ) 9 10-- If it's a table with numeric indices, it has children 11if type ( data ) == "table" and # data > 0 then 12flatten_instructions ( data , full_name , result ) 13else 14-- Add the current instruction 15table . insert ( result , full_name ) 16end 17end 18end 19 20return result 21end 22 23-- Load instruction definitions 24local function load_instructions ( filename ) 25local chunk , err =loadfile ( filename ) 26if not chunk then 27error ( "Failed to load instruction file: " .. filename .. " - " .. ( err or "unknown error" )) 28end 29 30-- Just execute it normally 31local result =chunk () 32 33-- If the file sets a global 'insts', use that 34if result . insts then 35return result . insts 36end 37 38error ( "Instruction file must return a table with 'insts' entry" ) 39end 40 41-- Load stable names table 42local function load_stable_names ( filename ) 43local file =io . open ( filename , "r" ) 44if not file then 45-- File doesn't exist, return empty table 46return {} 47end 48file : close () 49 50local chunk , err =loadfile ( filename ) 51if not chunk then 52error ( "Failed to load stable names file: " .. filename .. " - " .. ( err or "unknown error" )) 53end 54 55local result =chunk () 56 57-- Validate structure 58if type ( result ) ~= "table" then 59error ( "Stable names file must return a table" ) 60end 61 62for name , id in pairs ( result ) do 63if type ( name ) ~= "string" then 64error ( string . format ( "Invalid key: expected string, got %s" , type ( name ))) 65end 66if type ( id ) ~= "number" then 67error ( string . format ( "Invalid value for '%s': expected number, got %s" , name , type ( id ))) 68end 69end 70 71return result 72end 73 74-- Save stable names table 75local function save_stable_names ( filename , stable_names ) 76local file , err =io . open ( filename , "w" ) 77if not file then 78error ( "Failed to open file for writing: " .. filename .. " - " .. ( err or "unknown error" )) 79end 80 81file : write ( "-- This file is machine generated! any entries written below will be preserved,\n" ) 82file : write ( "-- but things like comments or anything outside the schema won't be preserved\n" ) 83file : write ( "return {\n" ) 84 85-- Sort by ID for consistent output 86local sorted_entries ={} 87for name , id in pairs ( stable_names ) do 88table . insert ( sorted_entries , { name =name , id =id } ) 89end 90table . sort ( sorted_entries , function ( a , b ) 91return a . id < b . id 92end ) 93 94for _ , entry in ipairs ( sorted_entries ) do 95-- Escape quotes in name 96local escaped_name =entry . name : gsub ( '"' , '\\"' ) 97file : write ( string . format ( '\t["%s"] = %d,\n' , escaped_name , entry . id )) 98end 99file : write ( "}\n" ) 100file : close () 101end 102 103-- Check for unique IDs 104local function check_unique_ids ( stable_names ) 105local seen_ids ={} 106local duplicates ={} 107 108for name , id in pairs ( stable_names ) do 109if seen_ids [ id ] then 110if not duplicates [ id ] then 111duplicates [ id ] ={ seen_ids [ id ] } 112end 113table . insert ( duplicates [ id ], name ) 114else 115seen_ids [ id ] =name 116end 117end 118 119return duplicates 120end 121 122-- Check bijection 123local function check_bijection ( inst_names , stable_names ) 124local missing_from_stable ={} 125local extra_in_stable ={} 126 127-- Check for instructions missing from stable names 128for _ , name in ipairs ( inst_names ) do 129if stable_names [ name ] == nil then 130table . insert ( missing_from_stable , name ) 131end 132end 133 134-- Check for stable names not in instructions 135local inst_name_set ={} 136for _ , name in ipairs ( inst_names ) do 137inst_name_set [ name ] =true 138end 139 140for name , _ in pairs ( stable_names ) do 141if not inst_name_set [ name ] then 142table . insert ( extra_in_stable , name ) 143end 144end 145 146return missing_from_stable , extra_in_stable 147end 148 149-- Get next available ID 150local function get_next_id ( stable_names ) 151local max_id =- 1 152for _ , id in pairs ( stable_names ) do 153if id > max_id then 154max_id =id 155end 156end 157return max_id + 1 158end 159 160-- Print usage 161local function print_usage () 162( "Usage: lua check_instructions.lua check|update [inst_file] [stable_file]" ) 163( "Commands:" ) 164( " check - Check bijection and uniqueness (default)" ) 165( " update - Add missing instructions to stable names" ) 166end 167 168-- Main program 169local function main ( args ) 170local command =args [ 1 ] or "check" 171local inst_file =args [ 2 ] or "source/slang/slang-ir-insts.lua" 172local stable_file =args [ 3 ] or "source/slang/slang-ir-insts-stable-names.lua" 173 174-- Validate command 175local valid_commands ={ check =true , update =true } 176if not valid_commands [ command ] then 177( "ERROR: Invalid command: " .. command ) 178print_usage () 179return 1 180end 181 182-- Load data with error handling 183local ok , insts_or_err =pcall ( load_instructions , inst_file ) 184if not ok then 185( "ERROR: " .. insts_or_err ) 186return 1 187end 188local insts =insts_or_err 189 190ok , stable_names =pcall ( load_stable_names , stable_file ) 191if not ok then 192( "ERROR: " .. stable_names ) 193return 1 194end 195 196-- Flatten instruction hierarchy 197local inst_names =flatten_instructions ( insts ) 198 199local has_errors =false 200 201if command == "check" or command == "all" then 202( "=== Checking stable names ===" ) 203 204-- Check unique IDs 205local duplicate_ids =check_unique_ids ( stable_names ) 206if next ( duplicate_ids ) then 207has_errors =true 208( "ERROR: Duplicate IDs found:" ) 209for id , names in pairs ( duplicate_ids ) do 210( string . format ( " - ID %d used by: %s" , id , table . concat ( names , ", " ))) 211end 212else 213( "✓ All IDs are unique" ) 214end 215 216-- Check bijection 217local missing , extra =check_bijection ( inst_names , stable_names ) 218 219if # missing > 0 then 220has_errors =true 221( string . format ( "ERROR: %d instructions missing from stable names:" , # missing )) 222for _ , name in ipairs ( missing ) do 223( " - " .. name ) 224end 225else 226( "✓ All instructions have stable names" ) 227end 228 229if # extra > 0 then 230( string . format ( "WARNING: %d extra entries in stable names (not in instructions):" , # extra )) 231for _ , name in ipairs ( extra ) do 232( " - " .. name ) 233end 234else 235( "✓ No extra entries in stable names" ) 236end 237 238if not has_errors and # extra == 0 then 239( "✓ Is a bijection" ) 240end 241end 242 243if command == "update" or command == "all" then 244( "=== Updating stable names ===" ) 245 246-- Don't update if there are errors 247if has_errors then 248( "ERROR: Cannot update due to errors in existing stable names" ) 249return 1 250end 251 252local missing , _ =check_bijection ( inst_names , stable_names ) 253 254if # missing > 0 then 255-- Add missing instructions 256local next_id =get_next_id ( stable_names ) 257 258for _ , name in ipairs ( missing ) do 259stable_names [ name ] =next_id 260next_id =next_id + 1 261end 262 263-- Save updated file 264local ok , err =pcall ( save_stable_names , stable_file , stable_names ) 265if not ok then 266( "ERROR: Failed to save: " .. err ) 267return 1 268end 269 270( string . format ( "Added %d new instructions to %s" , # missing , stable_file )) 271else 272( "No missing instructions to add" ) 273end 274end 275 276return has_errors and 1 or 0 277end 278 279-- Run the program 280os . exit ( main ( arg ) or 0 )