仔细看一下刚才的错误,我们发现
error: line 0: No OpEntryPoint instruction was found. This is only allowed if the Linkage capability is being used.
意思是没有入口,我们是要作为一个库吗? 显然不是,所以我们需要一个入口点
if fn_def.is_pub {
self.builder.entry_point(spirv::ExecutionModel::GLCompute, func_id, fn_def.name.as_str(), &self.interfaces);
self.builder.execution_mode(func_id, spirv::ExecutionMode::LocalSize, [8, 8, 8]);
}
复制代码
我们把 pub 函数作为入口点输出,注意后面的 spirv::ExecutionMode::LocalSize, [8, 8, 8]
这个设定了 spirv 希望自己做到的 组内线程维度,也就是在一个组内,x, y, y 方向上的线程数,
我们暂时使用 8 , 8, 8 就是申明一个组 512 个线程 一般而言,这个数字 受到显卡硬件的限制,不会超过 1024
再次运行之后,我们发现了新的错误,意思是 ID 为 8 的函数没有定义,我们看看 id 8 的名字是
好吧,这个是我们想要引用的系统内建函数,但是在编译的时候没有找到,所以生成了一个空的函数体,这个是不对的,我们要在 Builder 里面先内建好系统内置函数,然后在 Call 的时候 调用这个内建的函数,或者说内建的代码生成器
简单的办法是在 Call 的时候 不仅仅记录 ID 还要记录名字,但是这样太复杂了,我们采用简单的方案,导入函数的时候,如果没有函数体,直接装入一个空的 函数定义,以后如果有定义的函数 将函数 ID 换成 Some(id)
这样在调用的时候 如果是 Some(id) 则生成 call 函数
如果 是 None 则调用 Builder 的特定方法 生成代码
#[derive(Debug, Default, Clone, PartialEq, Eq)]
pub struct FnDef {
pub name: SmolStr,
pub args: Vec<Type>,
pub ret: Box<Type>,
}
复制代码
函数定义 数组如下
fns: Vec<(FnDef, Option<u32>)>,
复制代码
然后是调用代码
Statement::Call(func, args, ret_val) => {
if let Symbol::Fn(fn_idx) = func { //以后需要检查 参数数目和类型
if let Some(func_id) = self.fns[*fn_idx].1 { //有定义的函数 则生成调用指令
//首先把参数生成为 SSA ID
//let r = self.builder.function_call(ty_id, None, id, args)?;
//*self.get_mut(ret) = (r, ty_id, ty.clone(), None);
} else {
let func_name = self.fns[*fn_idx].0.name.clone();
self.call_native(func_name.as_str(), args, ret_val);
}
}
}
复制代码
call_native 长这样 我们先给个框架 在慢慢填充
pub fn call_native(&mut self, name: &str, args: &Vec<Symbol>, ret_val: &Symbol) {
match name {
"spirv_group"=> {
}
_=> {}
}
}
复制代码
评论