smokes: add curated LLVM runner; archive legacy smokes; PHI-off unified across Bridge/Builder; LLVM resolver tracing; minimal Throw lowering; config env getters; dev profile and root cleaner; docs updated; CI workflow runs curated LLVM (PHI-on/off)
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
#![cfg(feature = "wasm-backend")]
|
||||
/*!
|
||||
* WASM String Constants Test - Validates Issue #65 implementation
|
||||
*
|
||||
*
|
||||
* Tests string constant support in WASM backend:
|
||||
* - ConstValue::String handling in generate_const
|
||||
* - Data segment generation for string literals
|
||||
@ -9,11 +9,11 @@
|
||||
* - WAT generation includes data segments and string allocation
|
||||
*/
|
||||
|
||||
use nyash_rust::mir::{
|
||||
MirModule, MirFunction, FunctionSignature, MirType, EffectMask,
|
||||
BasicBlock, BasicBlockId, ValueId, MirInstruction, ConstValue
|
||||
};
|
||||
use nyash_rust::backend::wasm::WasmBackend;
|
||||
use nyash_rust::mir::{
|
||||
BasicBlock, BasicBlockId, ConstValue, EffectMask, FunctionSignature, MirFunction,
|
||||
MirInstruction, MirModule, MirType, ValueId,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_wasm_string_constant_basic() {
|
||||
@ -22,34 +22,58 @@ fn test_wasm_string_constant_basic() {
|
||||
// %str = const "Hello, WASM!"
|
||||
// return %str // Should return StringBox pointer
|
||||
// }
|
||||
|
||||
|
||||
let mut backend = WasmBackend::new();
|
||||
let mir_module = build_string_const_mir_module();
|
||||
|
||||
|
||||
// Generate WAT text for debugging
|
||||
let wat_result = backend.compile_to_wat(mir_module.clone());
|
||||
assert!(wat_result.is_ok(), "WAT generation should succeed for string constants");
|
||||
|
||||
assert!(
|
||||
wat_result.is_ok(),
|
||||
"WAT generation should succeed for string constants"
|
||||
);
|
||||
|
||||
let wat_text = wat_result.unwrap();
|
||||
|
||||
|
||||
// Verify WAT contains expected elements for string support
|
||||
assert!(wat_text.contains("(module"), "Should contain module declaration");
|
||||
assert!(wat_text.contains("memory"), "Should contain memory declaration");
|
||||
assert!(wat_text.contains("data"), "Should contain data segment for string literal");
|
||||
assert!(wat_text.contains("\\48\\65\\6c\\6c\\6f"), "Should contain UTF-8 bytes for 'Hello'");
|
||||
assert!(wat_text.contains("$alloc_stringbox"), "Should contain StringBox allocator");
|
||||
assert!(wat_text.contains("print_str"), "Should contain print_str import");
|
||||
|
||||
assert!(
|
||||
wat_text.contains("(module"),
|
||||
"Should contain module declaration"
|
||||
);
|
||||
assert!(
|
||||
wat_text.contains("memory"),
|
||||
"Should contain memory declaration"
|
||||
);
|
||||
assert!(
|
||||
wat_text.contains("data"),
|
||||
"Should contain data segment for string literal"
|
||||
);
|
||||
assert!(
|
||||
wat_text.contains("\\48\\65\\6c\\6c\\6f"),
|
||||
"Should contain UTF-8 bytes for 'Hello'"
|
||||
);
|
||||
assert!(
|
||||
wat_text.contains("$alloc_stringbox"),
|
||||
"Should contain StringBox allocator"
|
||||
);
|
||||
assert!(
|
||||
wat_text.contains("print_str"),
|
||||
"Should contain print_str import"
|
||||
);
|
||||
|
||||
// Verify string literal is properly embedded
|
||||
// (The assertion for UTF-8 bytes is above)
|
||||
|
||||
// Compile to WASM binary
|
||||
|
||||
// Compile to WASM binary
|
||||
let wasm_result = backend.compile_module(mir_module);
|
||||
if let Err(e) = &wasm_result {
|
||||
println!("WASM compilation error: {}", e);
|
||||
println!("Generated WAT:\n{}", wat_text);
|
||||
}
|
||||
assert!(wasm_result.is_ok(), "WASM compilation should succeed for string constants");
|
||||
assert!(
|
||||
wasm_result.is_ok(),
|
||||
"WASM compilation should succeed for string constants"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -57,35 +81,50 @@ fn test_wasm_string_constant_multiple() {
|
||||
// Test multiple string constants to verify data segment management
|
||||
// function main() {
|
||||
// %str1 = const "First"
|
||||
// %str2 = const "Second"
|
||||
// %str2 = const "Second"
|
||||
// %str3 = const "First" // Duplicate should reuse data segment
|
||||
// return %str1
|
||||
// }
|
||||
|
||||
|
||||
let mut backend = WasmBackend::new();
|
||||
let mir_module = build_multiple_string_const_mir_module();
|
||||
|
||||
|
||||
let wat_result = backend.compile_to_wat(mir_module.clone());
|
||||
assert!(wat_result.is_ok(), "WAT generation should succeed for multiple strings");
|
||||
|
||||
assert!(
|
||||
wat_result.is_ok(),
|
||||
"WAT generation should succeed for multiple strings"
|
||||
);
|
||||
|
||||
let wat_text = wat_result.unwrap();
|
||||
|
||||
|
||||
// Should contain both unique strings (in hex format)
|
||||
assert!(wat_text.contains("\\46\\69\\72\\73\\74"), "Should contain 'First' string in hex");
|
||||
assert!(wat_text.contains("\\53\\65\\63\\6f\\6e\\64"), "Should contain 'Second' string in hex");
|
||||
|
||||
assert!(
|
||||
wat_text.contains("\\46\\69\\72\\73\\74"),
|
||||
"Should contain 'First' string in hex"
|
||||
);
|
||||
assert!(
|
||||
wat_text.contains("\\53\\65\\63\\6f\\6e\\64"),
|
||||
"Should contain 'Second' string in hex"
|
||||
);
|
||||
|
||||
// Should have 2 data segments (First and Second, duplicate First reused)
|
||||
let data_count = wat_text.matches("(data").count();
|
||||
assert_eq!(data_count, 2, "Should have exactly 2 data segments for 2 unique strings");
|
||||
|
||||
assert_eq!(
|
||||
data_count, 2,
|
||||
"Should have exactly 2 data segments for 2 unique strings"
|
||||
);
|
||||
|
||||
let wasm_result = backend.compile_module(mir_module);
|
||||
assert!(wasm_result.is_ok(), "WASM compilation should succeed for multiple strings");
|
||||
assert!(
|
||||
wasm_result.is_ok(),
|
||||
"WASM compilation should succeed for multiple strings"
|
||||
);
|
||||
}
|
||||
|
||||
/// Build a MIR module with a single string constant
|
||||
fn build_string_const_mir_module() -> MirModule {
|
||||
let mut module = MirModule::new("test_string_const".to_string());
|
||||
|
||||
|
||||
// Create main function signature
|
||||
let main_signature = FunctionSignature {
|
||||
name: "main".to_string(),
|
||||
@ -93,26 +132,26 @@ fn build_string_const_mir_module() -> MirModule {
|
||||
return_type: MirType::Integer, // StringBox pointer as i32
|
||||
effects: EffectMask::PURE,
|
||||
};
|
||||
|
||||
|
||||
// Create basic block
|
||||
let entry_block = BasicBlockId::new(0);
|
||||
let mut main_function = MirFunction::new(main_signature, entry_block);
|
||||
let mut block = BasicBlock::new(entry_block);
|
||||
|
||||
|
||||
// %str = const "Hello, WASM!"
|
||||
let str_value = ValueId::new(0);
|
||||
block.instructions.push(MirInstruction::Const {
|
||||
dst: str_value,
|
||||
value: ConstValue::String("Hello, WASM!".to_string()),
|
||||
});
|
||||
|
||||
|
||||
// return %str
|
||||
block.terminator = Some(MirInstruction::Return {
|
||||
value: Some(str_value),
|
||||
});
|
||||
|
||||
|
||||
main_function.blocks.insert(entry_block, block);
|
||||
|
||||
|
||||
module.functions.insert("main".to_string(), main_function);
|
||||
module
|
||||
}
|
||||
@ -120,46 +159,46 @@ fn build_string_const_mir_module() -> MirModule {
|
||||
/// Build a MIR module with multiple string constants
|
||||
fn build_multiple_string_const_mir_module() -> MirModule {
|
||||
let mut module = MirModule::new("test_multiple_strings".to_string());
|
||||
|
||||
|
||||
let main_signature = FunctionSignature {
|
||||
name: "main".to_string(),
|
||||
params: vec![],
|
||||
return_type: MirType::Integer,
|
||||
effects: EffectMask::PURE,
|
||||
};
|
||||
|
||||
|
||||
let entry_block = BasicBlockId::new(0);
|
||||
let mut main_function = MirFunction::new(main_signature, entry_block);
|
||||
let mut block = BasicBlock::new(entry_block);
|
||||
|
||||
|
||||
// %str1 = const "First"
|
||||
let str1_value = ValueId::new(0);
|
||||
block.instructions.push(MirInstruction::Const {
|
||||
dst: str1_value,
|
||||
value: ConstValue::String("First".to_string()),
|
||||
});
|
||||
|
||||
|
||||
// %str2 = const "Second"
|
||||
let str2_value = ValueId::new(1);
|
||||
block.instructions.push(MirInstruction::Const {
|
||||
dst: str2_value,
|
||||
value: ConstValue::String("Second".to_string()),
|
||||
});
|
||||
|
||||
|
||||
// %str3 = const "First" (duplicate)
|
||||
let str3_value = ValueId::new(2);
|
||||
block.instructions.push(MirInstruction::Const {
|
||||
dst: str3_value,
|
||||
value: ConstValue::String("First".to_string()),
|
||||
});
|
||||
|
||||
|
||||
// return %str1
|
||||
block.terminator = Some(MirInstruction::Return {
|
||||
value: Some(str1_value),
|
||||
});
|
||||
|
||||
|
||||
main_function.blocks.insert(entry_block, block);
|
||||
|
||||
|
||||
module.functions.insert("main".to_string(), main_function);
|
||||
module
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user