Implement integer multiplication

This commit is contained in:
Andrzej Janik 2020-07-25 00:57:54 +02:00
parent 18e5147fdc
commit b068a89c38
8 changed files with 1201 additions and 995 deletions

View file

@ -11,5 +11,5 @@ members = [
]
[patch.crates-io]
rspirv = { git = 'https://github.com/vosen/rspirv', branch = 'notcuda' }
spirv_headers = { git = 'https://github.com/vosen/rspirv', branch = 'notcuda' }
rspirv = { git = 'https://github.com/vosen/rspirv', rev = '4523d54d785faff59c1e928dd1f210c531a70258' }
spirv_headers = { git = 'https://github.com/vosen/rspirv', rev = '4523d54d785faff59c1e928dd1f210c531a70258' }

View file

@ -1,6 +1,9 @@
use crate::ptx;
use crate::translate;
use rspirv::{binary::Disassemble, dr::{Block, Function, Instruction, Loader, Operand}};
use rspirv::{
binary::Assemble,
dr::{Block, Function, Instruction, Loader, Operand},
};
use spirv_headers::Word;
use spirv_tools_sys::{
spv_binary, spv_endianness_t, spv_parsed_instruction_t, spv_result_t, spv_target_env,
@ -37,9 +40,9 @@ macro_rules! test_ptx {
}
test_ptx!(ld_st, [1u64], [1u64]);
//test_ptx!(mov, [1u64], [1u64]);
//test_ptx!(mul_lo, [1u64], [2u64]);
//test_ptx!(mul_hi, [u64::max_value()], [1u64]);
test_ptx!(mov, [1u64], [1u64]);
test_ptx!(mul_lo, [1u64], [2u64]);
test_ptx!(mul_hi, [u64::max_value()], [1u64]);
struct DisplayError<T: Display + Debug> {
err: T,
@ -155,9 +158,31 @@ fn test_spvtxt_assert<'a>(
let mut loader = Loader::new();
rspirv::binary::parse_words(&parsed_spirv, &mut loader)?;
let spvtxt_mod = loader.module();
unsafe { spirv_tools::spvBinaryDestroy(spv_binary) };
if !is_spirv_fn_equal(&ptx_mod.functions[0], &spvtxt_mod.functions[0]) {
panic!(ptx_mod.disassemble())
// We could simply use ptx_mod.disassemble, but SPIRV-Tools text formattinmg is so much nicer
let spv_from_ptx_binary = ptx_mod.assemble();
let mut spv_text: spirv_tools::spv_text = ptr::null_mut();
let result = unsafe {
spirv_tools::spvBinaryToText(
spv_context,
spv_from_ptx_binary.as_ptr(),
spv_from_ptx_binary.len(),
(spirv_tools::spv_binary_to_text_options_t::SPV_BINARY_TO_TEXT_OPTION_INDENT | spirv_tools::spv_binary_to_text_options_t::SPV_BINARY_TO_TEXT_OPTION_NO_HEADER | spirv_tools::spv_binary_to_text_options_t::SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES).0,
&mut spv_text as *mut _,
ptr::null_mut()
)
};
assert_eq!(result, spv_result_t::SPV_SUCCESS);
let raw_text = unsafe {
std::slice::from_raw_parts((*spv_text).str_ as *const u8, (*spv_text).length)
};
let spv_from_ptx_text = unsafe { str::from_utf8_unchecked(raw_text) };
// TODO: stop leaking kernel text
unsafe { spirv_tools::spvContextDestroy(spv_context) };
panic!(spv_from_ptx_text);
}
unsafe { spirv_tools::spvContextDestroy(spv_context) };
Ok(())
}

View file

@ -1,26 +1,43 @@
OpCapability GenericPointer
OpCapability Linkage
OpCapability Addresses
OpCapability Kernel
OpCapability Int64
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %5 "mov"
%2 = OpTypeVoid
%3 = OpTypeInt 64 0
%4 = OpTypeFunction %2 %3 %3
%19 = OpTypePointer Generic %3
%5 = OpFunction %2 None %4
%6 = OpFunctionParameter %3
%7 = OpFunctionParameter %3
%18 = OpLabel
%13 = OpCopyObject %3 %6
%14 = OpCopyObject %3 %7
%15 = OpConvertUToPtr %19 %13
%16 = OpLoad %3 %15
%100 = OpCopyObject %3 %16
%17 = OpConvertUToPtr %19 %14
OpStore %17 %100
OpReturn
OpFunctionEnd
; SPIR-V
; Version: 1.5
; Generator: Khronos SPIR-V Tools Assembler; 0
; Bound: 23
; Schema: 0
OpCapability GenericPointer
OpCapability Linkage
OpCapability Addresses
OpCapability Kernel
OpCapability Int64
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %2 "mov"
%void = OpTypeVoid
%ulong = OpTypeInt 64 0
%5 = OpTypeFunction %void %ulong %ulong
%_ptr_Function_ulong = OpTypePointer Function %ulong
%_ptr_Generic_ulong = OpTypePointer Generic %ulong
%2 = OpFunction %void None %5
%8 = OpFunctionParameter %ulong
%9 = OpFunctionParameter %ulong
%10 = OpLabel
%11 = OpVariable %_ptr_Function_ulong Function
%12 = OpVariable %_ptr_Function_ulong Function
%13 = OpVariable %_ptr_Function_ulong Function
%14 = OpVariable %_ptr_Function_ulong Function
OpStore %11 %8
OpStore %12 %9
%15 = OpLoad %ulong %11
%16 = OpConvertUToPtr %_ptr_Generic_ulong %15
%17 = OpLoad %ulong %16
OpStore %13 %17
%18 = OpLoad %ulong %13
%19 = OpCopyObject %ulong %18
OpStore %14 %19
%20 = OpLoad %ulong %12
%21 = OpLoad %ulong %14
%22 = OpConvertUToPtr %_ptr_Generic_ulong %20
OpStore %22 %21
OpReturn
OpFunctionEnd

View file

@ -1,26 +1,43 @@
OpCapability GenericPointer
OpCapability Linkage
OpCapability Addresses
OpCapability Kernel
OpCapability Int64
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %5 "mul_hi"
%2 = OpTypeVoid
%3 = OpTypeInt 64 0
%4 = OpTypeFunction %2 %3 %3
%19 = OpTypePointer Generic %3
%5 = OpFunction %2 None %4
%6 = OpFunctionParameter %3
%7 = OpFunctionParameter %3
%18 = OpLabel
%13 = OpCopyObject %3 %6
%14 = OpCopyObject %3 %7
%15 = OpConvertUToPtr %19 %13
%16 = OpLoad %3 %15
%100 = OpCopyObject %3 %16
%17 = OpConvertUToPtr %19 %14
OpStore %17 %100
OpReturn
OpFunctionEnd
; SPIR-V
; Version: 1.5
; Generator: Khronos SPIR-V Tools Assembler; 0
; Bound: 24
; Schema: 0
OpCapability GenericPointer
OpCapability Linkage
OpCapability Addresses
OpCapability Kernel
OpCapability Int64
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %2 "mul_hi"
%void = OpTypeVoid
%ulong = OpTypeInt 64 0
%5 = OpTypeFunction %void %ulong %ulong
%_ptr_Function_ulong = OpTypePointer Function %ulong
%_ptr_Generic_ulong = OpTypePointer Generic %ulong
%ulong_2 = OpConstant %ulong 2
%2 = OpFunction %void None %5
%9 = OpFunctionParameter %ulong
%10 = OpFunctionParameter %ulong
%11 = OpLabel
%12 = OpVariable %_ptr_Function_ulong Function
%13 = OpVariable %_ptr_Function_ulong Function
%14 = OpVariable %_ptr_Function_ulong Function
%15 = OpVariable %_ptr_Function_ulong Function
OpStore %12 %9
OpStore %13 %10
%16 = OpLoad %ulong %12
%17 = OpConvertUToPtr %_ptr_Generic_ulong %16
%18 = OpLoad %ulong %17
OpStore %14 %18
%19 = OpLoad %ulong %14
%20 = OpExtInst %ulong %1 u_mul_hi %19 %ulong_2
OpStore %15 %20
%21 = OpLoad %ulong %13
%22 = OpLoad %ulong %15
%23 = OpConvertUToPtr %_ptr_Generic_ulong %21
OpStore %23 %22
OpReturn
OpFunctionEnd

View file

@ -1,26 +1,38 @@
OpCapability GenericPointer
OpCapability Linkage
OpCapability Addresses
OpCapability Kernel
OpCapability Int64
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %5 "mul_lo"
%2 = OpTypeVoid
%3 = OpTypeInt 64 0
%4 = OpTypeFunction %2 %3 %3
%19 = OpTypePointer Generic %3
%5 = OpFunction %2 None %4
%6 = OpFunctionParameter %3
%7 = OpFunctionParameter %3
%18 = OpLabel
%13 = OpCopyObject %3 %6
%14 = OpCopyObject %3 %7
%15 = OpConvertUToPtr %19 %13
%16 = OpLoad %3 %15
%100 = OpCopyObject %3 %16
%17 = OpConvertUToPtr %19 %14
OpStore %17 %100
OpReturn
OpFunctionEnd
OpCapability GenericPointer
OpCapability Linkage
OpCapability Addresses
OpCapability Kernel
OpCapability Int64
OpCapability Int8
%1 = OpExtInstImport "OpenCL.std"
OpMemoryModel Physical64 OpenCL
OpEntryPoint Kernel %5 "mul_lo"
%void = OpTypeVoid
%ulong = OpTypeInt 64 0
%4 = OpTypeFunction %void %ulong %ulong
%_ptr_Function_ulong = OpTypePointer Function %ulong
%_ptr_Generic_ulong = OpTypePointer Generic %ulong
%ulong_2 = OpConstant %ulong 2
%5 = OpFunction %void None %4
%6 = OpFunctionParameter %ulong
%7 = OpFunctionParameter %ulong
%21 = OpLabel
%8 = OpVariable %_ptr_Function_ulong Function
%9 = OpVariable %_ptr_Function_ulong Function
%10 = OpVariable %_ptr_Function_ulong Function
%11 = OpVariable %_ptr_Function_ulong Function
OpStore %8 %6
OpStore %9 %7
%12 = OpLoad %ulong %8
%19 = OpConvertUToPtr %_ptr_Generic_ulong %12
%13 = OpLoad %ulong %19
OpStore %10 %13
%14 = OpLoad %ulong %10
%15 = OpIMul %ulong %14 %ulong_2
OpStore %11 %15
%16 = OpLoad %ulong %9
%17 = OpLoad %ulong %11
%20 = OpConvertUToPtr %_ptr_Generic_ulong %16
OpStore %20 %17
OpReturn
OpFunctionEnd

View file

@ -107,11 +107,11 @@ pub fn to_spirv_module(ast: ast::Module) -> Result<dr::Module, dr::Error> {
builder.set_version(1, 0);
emit_capabilities(&mut builder);
emit_extensions(&mut builder);
emit_extended_instruction_sets(&mut builder);
let opencl_id = emit_opencl_import(&mut builder);
emit_memory_model(&mut builder);
let mut map = TypeWordMap::new(&mut builder);
for f in ast.functions {
emit_function(&mut builder, &mut map, f)?;
emit_function(&mut builder, &mut map, opencl_id, f)?;
}
Ok(builder.module())
}
@ -132,8 +132,8 @@ fn emit_capabilities(builder: &mut dr::Builder) {
fn emit_extensions(_: &mut dr::Builder) {}
fn emit_extended_instruction_sets(builder: &mut dr::Builder) {
builder.ext_inst_import("OpenCL.std");
fn emit_opencl_import(builder: &mut dr::Builder) -> spirv::Word {
builder.ext_inst_import("OpenCL.std")
}
fn emit_memory_model(builder: &mut dr::Builder) {
@ -146,6 +146,7 @@ fn emit_memory_model(builder: &mut dr::Builder) {
fn emit_function<'a>(
builder: &mut dr::Builder,
map: &mut TypeWordMap,
opencl_id: spirv::Word,
f: ast::Function<'a>,
) -> Result<spirv::Word, rspirv::dr::Error> {
let func_type = get_function_type(builder, map, &f.args);
@ -158,7 +159,7 @@ fn emit_function<'a>(
let id_offset = builder.reserve_ids(unique_ids);
emit_function_args(builder, id_offset, map, &f.args);
apply_id_offset(&mut func_body, id_offset);
emit_function_body_ops(builder, map, &func_body)?;
emit_function_body_ops(builder, map, opencl_id, &func_body)?;
builder.end_function()?;
Ok(func_id)
}
@ -265,7 +266,9 @@ fn insert_mem_ssa_statements(
match s {
Statement::Instruction(inst) => match inst {
Instruction::Ld(
ld @ ast::LdData {
ld
@
ast::LdData {
state_space: ast::LdStateSpace::Param,
..
},
@ -638,6 +641,7 @@ fn collect_label_ids<'a>(
fn emit_function_body_ops(
builder: &mut dr::Builder,
map: &mut TypeWordMap,
opencl: spirv::Word,
func: &[ExpandedStatement],
) -> Result<(), dr::Error> {
for s in func {
@ -658,7 +662,36 @@ fn emit_function_body_ops(
}
builder.variable(type_id, Some(*id), spirv::StorageClass::Function, None);
}
Statement::Constant(_) => todo!(),
Statement::Constant(cnst) => {
let typ_id = map.get_or_add_scalar(builder, cnst.typ);
match cnst.typ {
ast::ScalarType::B8 | ast::ScalarType::U8 => {
builder.constant_u32(typ_id, Some(cnst.dst), cnst.value as u8 as u32);
}
ast::ScalarType::B16 | ast::ScalarType::U16 => {
builder.constant_u32(typ_id, Some(cnst.dst), cnst.value as u16 as u32);
}
ast::ScalarType::B32 | ast::ScalarType::U32 => {
builder.constant_u32(typ_id, Some(cnst.dst), cnst.value as u32);
}
ast::ScalarType::B64 | ast::ScalarType::U64 => {
builder.constant_u64(typ_id, Some(cnst.dst), cnst.value as u64);
}
ast::ScalarType::S8 => {
builder.constant_u32(typ_id, Some(cnst.dst), cnst.value as i8 as u32);
}
ast::ScalarType::S16 => {
builder.constant_u32(typ_id, Some(cnst.dst), cnst.value as i16 as u32);
}
ast::ScalarType::S32 => {
builder.constant_u32(typ_id, Some(cnst.dst), cnst.value as i32 as u32);
}
ast::ScalarType::S64 => {
builder.constant_u64(typ_id, Some(cnst.dst), cnst.value as i64 as u64);
}
_ => unreachable!(),
}
}
Statement::Converison(cv) => emit_implicit_conversion(builder, map, cv)?,
Statement::Conditional(bra) => {
builder.branch_conditional(bra.predicate, bra.if_true, bra.if_false, [])?;
@ -700,17 +733,14 @@ fn emit_function_body_ops(
}
Instruction::Mul(mul, arg) => match mul.desc {
ast::MulDescriptor::Int(ref ctr) => {
emit_mul_int(builder, map, mul.typ, ctr, arg)
emit_mul_int(builder, map, opencl, mul.typ, ctr, arg)?;
}
ast::MulDescriptor::Float(_) => todo!(),
},
_ => todo!(),
},
Statement::LoadVar(arg, typ) => {
let type_id = map.get_or_add(
builder,
SpirvType::from(*typ),
);
let type_id = map.get_or_add(builder, SpirvType::from(*typ));
builder.load(type_id, Some(arg.dst), arg.src, None, [])?;
}
Statement::StoreVar(arg, typ) => {
@ -722,14 +752,36 @@ fn emit_function_body_ops(
}
fn emit_mul_int(
_builder: &mut dr::Builder,
_map: &mut TypeWordMap,
_typ: ast::Type,
_ctr: &ast::MulIntControl,
_arg: &Arg3,
) {
//let inst_type = map.get_or_add(builder, SpirvType::from(typ));
//builder.i_mul(inst_type, Some(arg.dst), Some(arg.src1), Some(arg.src2));
builder: &mut dr::Builder,
map: &mut TypeWordMap,
opencl: spirv::Word,
typ: ast::Type,
ctr: &ast::MulIntControl,
arg: &Arg3,
) -> Result<(), dr::Error> {
let inst_type = map.get_or_add(builder, SpirvType::from(typ));
match ctr {
ast::MulIntControl::Low => {
builder.i_mul(inst_type, Some(arg.dst), arg.src1, arg.src2)?;
}
ast::MulIntControl::High => {
let ocl_mul_hi = match typ.try_as_scalar().unwrap().kind() {
ScalarKind::Signed => spirv::CLOp::s_mul_hi,
ScalarKind::Unsigned => spirv::CLOp::u_mul_hi,
ScalarKind::Float => unreachable!(),
ScalarKind::Byte => unreachable!(),
};
builder.ext_inst(
inst_type,
Some(arg.dst),
1,
ocl_mul_hi as spirv::Word,
[arg.src1, arg.src2],
)?;
}
ast::MulIntControl::Wide => todo!(),
}
Ok(())
}
fn emit_implicit_conversion(

View file

@ -1 +1 @@
bindgen --whitelist-type="spv.*" --whitelist-function="spv.*" --size_t-is-usize --default-enum-style=rust ext/SPIRV-Tools/include/spirv-tools/libspirv.h -o lib.rs
bindgen --whitelist-type="spv.*" --whitelist-function="spv.*" --size_t-is-usize --default-enum-style=rust --bitfield-enum="spv_text_to_binary_options_t|spv_binary_to_text_options_t" ../ext/SPIRV-Tools/include/spirv-tools/libspirv.h -o src/spirv_tools.rs

File diff suppressed because it is too large Load diff