llvm(self): compare/branch/jump/ret に self 先頭規約を導入 + 自己受検スモーク追加\n\n- lang/src/llvm_ir/instructions/{compare,branch,jump,ret}.hako self化\n- quick/core/{compare,branch,jump,ret}/self_param_* 追加\n\nsmokes(stage-b): OOB を map missing read まで拡張(寛容に観測)\n- selfhost_stageb_oob_vm.sh 更新
This commit is contained in:
@ -4,41 +4,41 @@
|
||||
static box LLVMBranchInstructionBox {
|
||||
|
||||
// メインエントリーポイント - Pythonのlower_branch()に相当
|
||||
lower_branch(cond_vid, then_bid, else_bid) {
|
||||
return me.inst_branch(cond_vid, then_bid, else_bid)
|
||||
lower_branch(self, cond_vid, then_bid, else_bid) {
|
||||
return me.inst_branch(self, cond_vid, then_bid, else_bid)
|
||||
}
|
||||
|
||||
// 分岐命令の生成
|
||||
inst_branch(cond_vid, then_bid, else_bid) {
|
||||
inst_branch(self, cond_vid, then_bid, else_bid) {
|
||||
// JSON: {"op":"branch","cond":3,"then":1,"else":2}
|
||||
return "{\"op\":\"branch\",\"cond\":" + cond_vid + ",\"then\":" + then_bid + ",\"else\":" + else_bid + "}"
|
||||
}
|
||||
|
||||
// デバッグ用 - 生成された命令の確認
|
||||
debug_branch(cond_vid, then_bid, else_bid) {
|
||||
local json = me.lower_branch(cond_vid, then_bid, else_bid)
|
||||
debug_branch(self, cond_vid, then_bid, else_bid) {
|
||||
local json = me.lower_branch(self, cond_vid, then_bid, else_bid)
|
||||
print("Generated branch instruction: " + json)
|
||||
return json
|
||||
}
|
||||
|
||||
// 条件付きジャンプのヘルパー
|
||||
if_then_else(condition, then_block, else_block) {
|
||||
return me.inst_branch(condition, then_block, else_block)
|
||||
if_then_else(self, condition, then_block, else_block) {
|
||||
return me.inst_branch(self, condition, then_block, else_block)
|
||||
}
|
||||
|
||||
// 単純な条件分岐(true/false)
|
||||
simple_branch(cond_val, true_block, false_block) {
|
||||
simple_branch(self, cond_val, true_block, false_block) {
|
||||
// cond_val: 0=false, 1=true
|
||||
return me.inst_branch(cond_val, true_block, false_block)
|
||||
return me.inst_branch(self, cond_val, true_block, false_block)
|
||||
}
|
||||
|
||||
// 複数の分岐をまとめて生成
|
||||
batch_branch(branch_list) {
|
||||
batch_branch(self, branch_list) {
|
||||
local results = []
|
||||
local i = 0
|
||||
while i < branch_list.length() {
|
||||
local branch = branch_list[i]
|
||||
local json = me.lower_branch(branch.cond, branch.then_block, branch.else_block)
|
||||
local json = me.lower_branch(self, branch.cond, branch.then_block, branch.else_block)
|
||||
results.push(json)
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
static box LLVMCompareInstructionBox {
|
||||
|
||||
// メインエントリーポイント - Pythonのlower_compare()に相当
|
||||
lower_compare(op, lhs, rhs, dst) {
|
||||
lower_compare(self, op, lhs, rhs, dst) {
|
||||
// 比較演算子の検証
|
||||
if !me._is_valid_operator(op) {
|
||||
print("Warning: Invalid compare operator: " + op + ", defaulting to ==")
|
||||
@ -15,54 +15,54 @@ static box LLVMCompareInstructionBox {
|
||||
}
|
||||
|
||||
// 有効な比較演算子の検証
|
||||
_is_valid_operator(op) {
|
||||
_is_valid_operator(self, op) {
|
||||
return op == "==" || op == "!=" || op == "<" || op == ">" || op == "<=" || op == ">="
|
||||
}
|
||||
|
||||
// 比較命令の生成
|
||||
inst_compare(op, lhs, rhs, dst) {
|
||||
inst_compare(self, op, lhs, rhs, dst) {
|
||||
return "{\"op\":\"compare\",\"dst\":" + dst + ",\"operation\":\"" + op + "\",\"lhs\":" + lhs + ",\"rhs\":" + rhs + "}"
|
||||
}
|
||||
|
||||
// 各比較演算子の個別メソッド
|
||||
inst_eq(lhs, rhs, dst) {
|
||||
return me.inst_compare("==", lhs, rhs, dst)
|
||||
inst_eq(self, lhs, rhs, dst) {
|
||||
return me.inst_compare(self, "==", lhs, rhs, dst)
|
||||
}
|
||||
|
||||
inst_ne(lhs, rhs, dst) {
|
||||
return me.inst_compare("!=", lhs, rhs, dst)
|
||||
inst_ne(self, lhs, rhs, dst) {
|
||||
return me.inst_compare(self, "!=", lhs, rhs, dst)
|
||||
}
|
||||
|
||||
inst_lt(lhs, rhs, dst) {
|
||||
return me.inst_compare("<", lhs, rhs, dst)
|
||||
inst_lt(self, lhs, rhs, dst) {
|
||||
return me.inst_compare(self, "<", lhs, rhs, dst)
|
||||
}
|
||||
|
||||
inst_gt(lhs, rhs, dst) {
|
||||
return me.inst_compare(">", lhs, rhs, dst)
|
||||
inst_gt(self, lhs, rhs, dst) {
|
||||
return me.inst_compare(self, ">", lhs, rhs, dst)
|
||||
}
|
||||
|
||||
inst_le(lhs, rhs, dst) {
|
||||
return me.inst_compare("<=", lhs, rhs, dst)
|
||||
inst_le(self, lhs, rhs, dst) {
|
||||
return me.inst_compare(self, "<=", lhs, rhs, dst)
|
||||
}
|
||||
|
||||
inst_ge(lhs, rhs, dst) {
|
||||
return me.inst_compare(">=", lhs, rhs, dst)
|
||||
inst_ge(self, lhs, rhs, dst) {
|
||||
return me.inst_compare(self, ">=", lhs, rhs, dst)
|
||||
}
|
||||
|
||||
// デバッグ用 - 生成された命令の確認
|
||||
debug_compare(op, lhs, rhs, dst) {
|
||||
local json = me.lower_compare(op, lhs, rhs, dst)
|
||||
debug_compare(self, op, lhs, rhs, dst) {
|
||||
local json = me.lower_compare(self, op, lhs, rhs, dst)
|
||||
print("Generated compare instruction: " + json)
|
||||
return json
|
||||
}
|
||||
|
||||
// 複数の比較をまとめて生成(効率化)
|
||||
batch_compare(compare_list) {
|
||||
batch_compare(self, compare_list) {
|
||||
local results = []
|
||||
local i = 0
|
||||
while i < compare_list.length() {
|
||||
local cmp = compare_list[i]
|
||||
local json = me.lower_compare(cmp.op, cmp.lhs, cmp.rhs, cmp.dst)
|
||||
local json = me.lower_compare(self, cmp.op, cmp.lhs, cmp.rhs, cmp.dst)
|
||||
results.push(json)
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
@ -4,50 +4,50 @@
|
||||
static box LLVMJumpInstructionBox {
|
||||
|
||||
// メインエントリーポイント - Pythonのlower_jump()に相当
|
||||
lower_jump(target_bid) {
|
||||
return me.inst_jump(target_bid)
|
||||
lower_jump(self, target_bid) {
|
||||
return me.inst_jump(self, target_bid)
|
||||
}
|
||||
|
||||
// ジャンプ命令の生成
|
||||
inst_jump(target_bid) {
|
||||
inst_jump(self, target_bid) {
|
||||
// JSON: {"op":"jump","target":5}
|
||||
return "{\"op\":\"jump\",\"target\":" + target_bid + "}"
|
||||
}
|
||||
|
||||
// デバッグ用 - 生成された命令の確認
|
||||
debug_jump(target_bid) {
|
||||
local json = me.lower_jump(target_bid)
|
||||
debug_jump(self, target_bid) {
|
||||
local json = me.lower_jump(self, target_bid)
|
||||
print("Generated jump instruction: " + json)
|
||||
return json
|
||||
}
|
||||
|
||||
// ラベルへのジャンプ
|
||||
jump_to_label(label_id) {
|
||||
return me.inst_jump(label_id)
|
||||
jump_to_label(self, label_id) {
|
||||
return me.inst_jump(self, label_id)
|
||||
}
|
||||
|
||||
// ループヘッドへのジャンプ
|
||||
jump_loop_head(loop_block) {
|
||||
return me.inst_jump(loop_block)
|
||||
jump_loop_head(self, loop_block) {
|
||||
return me.inst_jump(self, loop_block)
|
||||
}
|
||||
|
||||
// ループ終了へのジャンプ
|
||||
jump_loop_end(exit_block) {
|
||||
return me.inst_jump(exit_block)
|
||||
jump_loop_end(self, exit_block) {
|
||||
return me.inst_jump(self, exit_block)
|
||||
}
|
||||
|
||||
// 関数終了へのジャンプ
|
||||
jump_to_epilogue(epilogue_block) {
|
||||
return me.inst_jump(epilogue_block)
|
||||
jump_to_epilogue(self, epilogue_block) {
|
||||
return me.inst_jump(self, epilogue_block)
|
||||
}
|
||||
|
||||
// 複数のジャンプをまとめて生成
|
||||
batch_jump(jump_list) {
|
||||
batch_jump(self, jump_list) {
|
||||
local results = []
|
||||
local i = 0
|
||||
while i < jump_list.length() {
|
||||
local jump = jump_list[i]
|
||||
local json = me.lower_jump(jump.target)
|
||||
local json = me.lower_jump(self, jump.target)
|
||||
results.push(json)
|
||||
i = i + 1
|
||||
}
|
||||
|
||||
@ -4,42 +4,42 @@
|
||||
static box LLVMRetInstructionBox {
|
||||
|
||||
// メインエントリーポイント - Pythonのlower_return()に相当
|
||||
lower_return(value_id) {
|
||||
lower_return(self, value_id) {
|
||||
if value_id == null || value_id == 0 {
|
||||
// Void return
|
||||
return me.inst_ret_void()
|
||||
return me.inst_ret_void(self)
|
||||
} else {
|
||||
// Value return
|
||||
return me.inst_ret_value(value_id)
|
||||
}
|
||||
return me.inst_ret_value(self, value_id)
|
||||
}
|
||||
}
|
||||
|
||||
// Void return命令
|
||||
inst_ret_void() {
|
||||
inst_ret_void(self) {
|
||||
return "{\"op\":\"ret\",\"value\":null}"
|
||||
}
|
||||
|
||||
// Value return命令
|
||||
inst_ret_value(value_id) {
|
||||
inst_ret_value(self, value_id) {
|
||||
return "{\"op\":\"ret\",\"value\":" + value_id + "}"
|
||||
}
|
||||
|
||||
// 定数値を返す(ショートカット)
|
||||
ret_const_i64(value) {
|
||||
ret_const_i64(self, value) {
|
||||
return "{\"op\":\"ret\",\"value\":null}" // 実際には定数命令 + ret命令が必要
|
||||
}
|
||||
|
||||
// デバッグ用 - 生成された命令の確認
|
||||
debug_ret(value_id) {
|
||||
local json = me.lower_return(value_id)
|
||||
debug_ret(self, value_id) {
|
||||
local json = me.lower_return(self, value_id)
|
||||
print("Generated ret instruction: " + json)
|
||||
return json
|
||||
}
|
||||
|
||||
// プログラム全体のreturn生成(定数+returnの組み合わせ)
|
||||
program_with_const_ret(const_value) {
|
||||
program_with_const_ret(self, const_value) {
|
||||
local const_inst = "{\"op\":\"const\",\"dst\":1,\"value\":{\"type\":\"i64\",\"value\":" + const_value + "}}"
|
||||
local ret_inst = me.inst_ret_value(1)
|
||||
local ret_inst = me.inst_ret_value(self, 1)
|
||||
|
||||
return "{ \"version\": 0, \"functions\": [ { \"name\": \"main\", \"params\": [], \"blocks\": [ { \"id\": 0, \"instructions\": [" +
|
||||
const_inst + "," +
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
# Verify LLVMBranchInstructionBox.lower_branch requires self and returns JSON
|
||||
|
||||
source "$(dirname "$0")/../../../lib/test_runner.sh"
|
||||
source "$(dirname "$0")/../../../lib/result_checker.sh"
|
||||
|
||||
require_env || exit 2
|
||||
preflight_plugins || exit 2
|
||||
|
||||
test_self_param_branch() {
|
||||
local src='
|
||||
using "lang/src/llvm_ir/instructions/branch.hako" as B
|
||||
box Main { static method main() {
|
||||
local s = new B.LLVMBranchInstructionBox().lower_branch(3, 1, 2)
|
||||
if s.contains("\"op\":\"branch\"") && s.contains("\"then\":1") { print(1) } else { print(0) }
|
||||
} }
|
||||
'
|
||||
local out
|
||||
out=$(run_nyash_vm -c "$src" 2>&1)
|
||||
check_exact "1" "$out" "self_param_branch"
|
||||
}
|
||||
|
||||
run_test "self_param_branch" test_self_param_branch
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
# Verify LLVMCompareInstructionBox.lower_compare requires self and returns JSON
|
||||
|
||||
source "$(dirname "$0")/../../../lib/test_runner.sh"
|
||||
source "$(dirname "$0")/../../../lib/result_checker.sh"
|
||||
|
||||
require_env || exit 2
|
||||
preflight_plugins || exit 2
|
||||
|
||||
test_self_param_compare() {
|
||||
local src='
|
||||
using "lang/src/llvm_ir/instructions/compare.hako" as C
|
||||
box Main { static method main() {
|
||||
local s = new C.LLVMCompareInstructionBox().lower_compare("<", 1, 2, 3)
|
||||
if s.contains("\"op\":\"compare\"") && s.contains("\"operation\":\"<\"") { print(1) } else { print(0) }
|
||||
} }
|
||||
'
|
||||
local out
|
||||
out=$(run_nyash_vm -c "$src" 2>&1)
|
||||
check_exact "1" "$out" "self_param_compare"
|
||||
}
|
||||
|
||||
run_test "self_param_compare" test_self_param_compare
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
# Verify LLVMJumpInstructionBox.lower_jump requires self and returns JSON
|
||||
|
||||
source "$(dirname "$0")/../../../lib/test_runner.sh"
|
||||
source "$(dirname "$0")/../../../lib/result_checker.sh"
|
||||
|
||||
require_env || exit 2
|
||||
preflight_plugins || exit 2
|
||||
|
||||
test_self_param_jump() {
|
||||
local src='
|
||||
using "lang/src/llvm_ir/instructions/jump.hako" as J
|
||||
box Main { static method main() {
|
||||
local s = new J.LLVMJumpInstructionBox().lower_jump(5)
|
||||
if s.contains("\"op\":\"jump\"") && s.contains("\"target\":5") { print(1) } else { print(0) }
|
||||
} }
|
||||
'
|
||||
local out
|
||||
out=$(run_nyash_vm -c "$src" 2>&1)
|
||||
check_exact "1" "$out" "self_param_jump"
|
||||
}
|
||||
|
||||
run_test "self_param_jump" test_self_param_jump
|
||||
|
||||
24
tools/smokes/v2/profiles/quick/core/ret/self_param_ret_vm.sh
Normal file
24
tools/smokes/v2/profiles/quick/core/ret/self_param_ret_vm.sh
Normal file
@ -0,0 +1,24 @@
|
||||
#!/bin/bash
|
||||
# Verify LLVMRetInstructionBox.lower_return requires self and returns JSON
|
||||
|
||||
source "$(dirname "$0")/../../../lib/test_runner.sh"
|
||||
source "$(dirname "$0")/../../../lib/result_checker.sh"
|
||||
|
||||
require_env || exit 2
|
||||
preflight_plugins || exit 2
|
||||
|
||||
test_self_param_ret() {
|
||||
local src='
|
||||
using "lang/src/llvm_ir/instructions/ret.hako" as R
|
||||
box Main { static method main() {
|
||||
local s = new R.LLVMRetInstructionBox().lower_return(7)
|
||||
if s.contains("\"op\":\"ret\"") && s.contains("\"value\":7") { print(1) } else { print(0) }
|
||||
} }
|
||||
'
|
||||
local out
|
||||
out=$(run_nyash_vm -c "$src" 2>&1)
|
||||
check_exact "1" "$out" "self_param_ret"
|
||||
}
|
||||
|
||||
run_test "self_param_ret" test_self_param_ret
|
||||
|
||||
@ -81,5 +81,31 @@ test_oob_array_write() {
|
||||
run_test "stageb_oob_array_read" test_oob_array_read
|
||||
run_test "stageb_oob_array_write" test_oob_array_write
|
||||
|
||||
exit 0
|
||||
# Map missing key (read) — accept error or 'null' as pass for now
|
||||
test_oob_map_missing_read() {
|
||||
local code='box Main { static method main() { local m={"a":1}; print(m["zzz"]); } }'
|
||||
local json
|
||||
json=$(hako_compile_to_mir_stageb "$code") || return 0
|
||||
if out=$(NYASH_QUIET=1 HAKO_QUIET=1 NYASH_CLI_VERBOSE=0 NYASH_NYRT_SILENT_RESULT=1 \
|
||||
"$ROOT/target/release/nyash" --json-file "$json" 2>&1); then
|
||||
local last
|
||||
last=$(printf '%s\n' "$out" | awk '/^(✅|ResultType|Result:)/{next} NF{last=$0} END{print last}')
|
||||
if [ "$last" = "null" ]; then
|
||||
log_success "map missing read returned null (accepted)"
|
||||
rm -f "$json"
|
||||
return 0
|
||||
else
|
||||
log_warn "map missing read returned '$last' (tolerated for now)"
|
||||
rm -f "$json"
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
log_success "map missing read produced error (accepted)"
|
||||
rm -f "$json"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
run_test "stageb_oob_map_missing_read" test_oob_map_missing_read
|
||||
|
||||
exit 0
|
||||
|
||||
Reference in New Issue
Block a user