mirror of
https://github.com/vosen/ZLUDA.git
synced 2025-09-23 09:49:01 +00:00
Support immediates in vector operands (#488)
This commit is contained in:
parent
b11c17a48b
commit
4306646739
16 changed files with 236 additions and 10 deletions
BIN
elf.o
Normal file
BIN
elf.o
Normal file
Binary file not shown.
|
@ -230,15 +230,33 @@ impl<'a, 'input> FlattenArguments<'a, 'input> {
|
||||||
|
|
||||||
fn vec_pack(
|
fn vec_pack(
|
||||||
&mut self,
|
&mut self,
|
||||||
vector_elements: Vec<SpirvWord>,
|
vector_elements: Vec<ast::RegOrImmediate<SpirvWord>>,
|
||||||
type_space: Option<(&ast::Type, ast::StateSpace)>,
|
type_space: Option<(&ast::Type, ast::StateSpace)>,
|
||||||
is_dst: bool,
|
is_dst: bool,
|
||||||
relaxed_type_check: bool,
|
relaxed_type_check: bool,
|
||||||
) -> Result<SpirvWord, TranslateError> {
|
) -> Result<SpirvWord, TranslateError> {
|
||||||
let (width, scalar_t, state_space) = match type_space {
|
let (width, scalar_t, state_space) = match type_space {
|
||||||
Some((ast::Type::Vector(width, scalar_t), space)) => (*width, *scalar_t, space),
|
Some((ast::Type::Vector(width, scalar_t), space)) => (*width, *scalar_t, space),
|
||||||
|
Some((ast::Type::Scalar(scalar_t), space))
|
||||||
|
if scalar_t.kind() == ast::ScalarKind::Bit =>
|
||||||
|
{
|
||||||
|
let type_ =
|
||||||
|
ast::ScalarType::from_size(scalar_t.size_of() / (vector_elements.len() as u8))
|
||||||
|
.ok_or_else(|| error_mismatched_type())?;
|
||||||
|
(vector_elements.len() as u8, type_, space)
|
||||||
|
}
|
||||||
_ => return Err(error_mismatched_type()),
|
_ => return Err(error_mismatched_type()),
|
||||||
};
|
};
|
||||||
|
let vector_elements = vector_elements
|
||||||
|
.into_iter()
|
||||||
|
.map(|element| match element {
|
||||||
|
ast::RegOrImmediate::Reg(name) => self.reg(name),
|
||||||
|
ast::RegOrImmediate::Imm(immediate_value) => self.immediate(
|
||||||
|
immediate_value,
|
||||||
|
Some((&ast::Type::Scalar(scalar_t), state_space)),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<_>, _>>()?;
|
||||||
let temporary_vector = self
|
let temporary_vector = self
|
||||||
.resolver
|
.resolver
|
||||||
.register_unnamed(Some((ast::Type::Vector(width, scalar_t), state_space)));
|
.register_unnamed(Some((ast::Type::Vector(width, scalar_t), state_space)));
|
||||||
|
|
|
@ -198,10 +198,15 @@ pub fn map_operand<T: Copy, Err>(
|
||||||
Some(ident) => ast::ParsedOperand::Reg(ident),
|
Some(ident) => ast::ParsedOperand::Reg(ident),
|
||||||
None => ast::ParsedOperand::VecMember(ident, member),
|
None => ast::ParsedOperand::VecMember(ident, member),
|
||||||
},
|
},
|
||||||
ast::ParsedOperand::VecPack(idents) => ast::ParsedOperand::VecPack(
|
ast::ParsedOperand::VecPack(elements) => ast::ParsedOperand::VecPack(
|
||||||
idents
|
elements
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|ident| Ok(fn_(ident, None)?.unwrap_or(ident)))
|
.map(|element| match element {
|
||||||
|
ast::RegOrImmediate::Reg(ident) => {
|
||||||
|
Ok(ast::RegOrImmediate::Reg(fn_(ident, None)?.unwrap_or(ident)))
|
||||||
|
}
|
||||||
|
ast::RegOrImmediate::Imm(imm) => Ok(ast::RegOrImmediate::Imm(imm)),
|
||||||
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?,
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
|
|
@ -613,6 +613,12 @@ struct ConstantDefinition {
|
||||||
pub value: ast::ImmediateValue,
|
pub value: ast::ImmediateValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for ConstantDefinition {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "zluda.constant{} {}", self.typ, self.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PtrAccess<T> {
|
pub struct PtrAccess<T> {
|
||||||
underlying_type: ast::Type,
|
underlying_type: ast::Type,
|
||||||
state_space: ast::StateSpace,
|
state_space: ast::StateSpace,
|
||||||
|
@ -629,6 +635,22 @@ struct RepackVectorDetails {
|
||||||
relaxed_type_check: bool,
|
relaxed_type_check: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for RepackVectorDetails {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let extract = if self.is_extract {
|
||||||
|
".extract"
|
||||||
|
} else {
|
||||||
|
".composite"
|
||||||
|
};
|
||||||
|
let relaxed = if self.relaxed_type_check {
|
||||||
|
".relaxed"
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
write!(f, "zluda.repack_vector{}{}{}", extract, relaxed, self.typ)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct FunctionPointerDetails {
|
struct FunctionPointerDetails {
|
||||||
dst: SpirvWord,
|
dst: SpirvWord,
|
||||||
src: SpirvWord,
|
src: SpirvWord,
|
||||||
|
|
22
ptx/src/pass/test/expand_operands/mod.rs
Normal file
22
ptx/src/pass/test/expand_operands/mod.rs
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
use crate::pass::{test::directive2_vec_to_string, *};
|
||||||
|
|
||||||
|
use super::test_pass;
|
||||||
|
|
||||||
|
macro_rules! test_expand_operands {
|
||||||
|
($test_name:ident) => {
|
||||||
|
test_pass!(run_expand_operands, $test_name);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_expand_operands(ptx: ptx_parser::Module) -> String {
|
||||||
|
// We run the minimal number of passes required to produce the input expected by expand_operands
|
||||||
|
let mut flat_resolver = GlobalStringIdentResolver2::new(SpirvWord(1));
|
||||||
|
let mut scoped_resolver = ScopedResolver::new(&mut flat_resolver);
|
||||||
|
let directives = normalize_identifiers2::run(&mut scoped_resolver, ptx.directives).unwrap();
|
||||||
|
let directives = normalize_predicates2::run(&mut flat_resolver, directives).unwrap();
|
||||||
|
let directives = expand_operands::run(&mut flat_resolver, directives).unwrap();
|
||||||
|
directive2_vec_to_string(&flat_resolver, directives)
|
||||||
|
}
|
||||||
|
|
||||||
|
test_expand_operands!(vector_operand);
|
||||||
|
test_expand_operands!(vector_operand_convert);
|
23
ptx/src/pass/test/expand_operands/vector_operand.ptx
Normal file
23
ptx/src/pass/test/expand_operands/vector_operand.ptx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
.version 6.5
|
||||||
|
.target sm_60
|
||||||
|
.address_size 64
|
||||||
|
|
||||||
|
.func (.reg .v2.b16 output) default (
|
||||||
|
.reg .b16 input
|
||||||
|
)
|
||||||
|
{
|
||||||
|
mov.v2.b16 output, {0x5678, input};
|
||||||
|
ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %%% output %%%
|
||||||
|
|
||||||
|
.func (.reg .v2 .b16 %2) %1 (
|
||||||
|
.reg .b16 %3
|
||||||
|
)
|
||||||
|
{
|
||||||
|
.b16.reg %4 = zluda.constant.b16 22136;
|
||||||
|
.v2.b16.reg %5 = zluda.repack_vector.composite.b16 %4, %3;
|
||||||
|
mov.v2.b16 %2, %5;
|
||||||
|
ret;
|
||||||
|
}
|
23
ptx/src/pass/test/expand_operands/vector_operand_convert.ptx
Normal file
23
ptx/src/pass/test/expand_operands/vector_operand_convert.ptx
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
.version 6.5
|
||||||
|
.target sm_60
|
||||||
|
.address_size 64
|
||||||
|
|
||||||
|
.func (.reg .b32 output) default (
|
||||||
|
.reg .b16 input
|
||||||
|
)
|
||||||
|
{
|
||||||
|
mov.b32 output, {0x5678, input};
|
||||||
|
ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %%% output %%%
|
||||||
|
|
||||||
|
.func (.reg .b32 %2) %1 (
|
||||||
|
.reg .b16 %3
|
||||||
|
)
|
||||||
|
{
|
||||||
|
.b16.reg %4 = zluda.constant.b16 22136;
|
||||||
|
.v2.b16.reg %5 = zluda.repack_vector.composite.b16 %4, %3;
|
||||||
|
mov.b32 %2, %5;
|
||||||
|
ret;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
.version 6.5
|
||||||
|
.target sm_30
|
||||||
|
.address_size 64
|
||||||
|
|
||||||
|
.func (.reg .b32 output) default (
|
||||||
|
.reg .v2.b16 input
|
||||||
|
)
|
||||||
|
{
|
||||||
|
mov.b32 output, input;
|
||||||
|
ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// %%% output %%%
|
||||||
|
|
||||||
|
.func (.reg .b32 %2) %1 (
|
||||||
|
.reg .v2 .b16 %3
|
||||||
|
)
|
||||||
|
{
|
||||||
|
.b32.reg %4 = zluda.convert_implicit.default.reg.b32.reg.v2.b16 %3;
|
||||||
|
mov.b32 %2, %4;
|
||||||
|
ret;
|
||||||
|
}
|
|
@ -21,3 +21,4 @@ fn run_insert_implicit_conversions(ptx: ptx_parser::Module) -> String {
|
||||||
|
|
||||||
test_insert_implicit_conversions!(default);
|
test_insert_implicit_conversions!(default);
|
||||||
test_insert_implicit_conversions!(default_reg_b32_reg_f16x2);
|
test_insert_implicit_conversions!(default_reg_b32_reg_f16x2);
|
||||||
|
test_insert_implicit_conversions!(default_reg_b32_reg_v2_b16);
|
||||||
|
|
|
@ -6,6 +6,7 @@ use std::{
|
||||||
path::Path,
|
path::Path,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod expand_operands;
|
||||||
mod insert_implicit_conversions;
|
mod insert_implicit_conversions;
|
||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -202,6 +203,8 @@ fn statement_to_string(
|
||||||
Statement::Variable(var) => format!("{}", var),
|
Statement::Variable(var) => format!("{}", var),
|
||||||
Statement::Instruction(instr) => format!("{}", instr),
|
Statement::Instruction(instr) => format!("{}", instr),
|
||||||
Statement::Conversion(conv) => format!("{}", conv),
|
Statement::Conversion(conv) => format!("{}", conv),
|
||||||
|
Statement::Constant(constant) => format!("{}", constant),
|
||||||
|
Statement::RepackVector(repack) => format!("{}", repack),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
};
|
};
|
||||||
let mut args_formatter = StatementFormatter::new(resolver);
|
let mut args_formatter = StatementFormatter::new(resolver);
|
||||||
|
|
31
ptx/src/test/ll/vector_operand.ll
Normal file
31
ptx/src/test/ll/vector_operand.ll
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
define amdgpu_kernel void @vector_operand(ptr addrspace(4) byref(i64) %"36", ptr addrspace(4) byref(i64) %"37") #0 {
|
||||||
|
%"38" = alloca i64, align 8, addrspace(5)
|
||||||
|
%"39" = alloca i64, align 8, addrspace(5)
|
||||||
|
%"40" = alloca i16, align 2, addrspace(5)
|
||||||
|
%"41" = alloca i32, align 4, addrspace(5)
|
||||||
|
br label %1
|
||||||
|
|
||||||
|
1: ; preds = %0
|
||||||
|
br label %"35"
|
||||||
|
|
||||||
|
"35": ; preds = %1
|
||||||
|
%"42" = load i64, ptr addrspace(4) %"36", align 8
|
||||||
|
store i64 %"42", ptr addrspace(5) %"38", align 8
|
||||||
|
%"43" = load i64, ptr addrspace(4) %"37", align 8
|
||||||
|
store i64 %"43", ptr addrspace(5) %"39", align 8
|
||||||
|
%"45" = load i64, ptr addrspace(5) %"38", align 8
|
||||||
|
%"50" = inttoptr i64 %"45" to ptr
|
||||||
|
%"44" = load i16, ptr %"50", align 2
|
||||||
|
store i16 %"44", ptr addrspace(5) %"40", align 2
|
||||||
|
%"46" = load i16, ptr addrspace(5) %"40", align 2
|
||||||
|
%"34" = insertelement <2 x i16> <i16 22136, i16 undef>, i16 %"46", i8 1
|
||||||
|
%"51" = bitcast <2 x i16> %"34" to i32
|
||||||
|
store i32 %"51", ptr addrspace(5) %"41", align 4
|
||||||
|
%"48" = load i64, ptr addrspace(5) %"39", align 8
|
||||||
|
%"49" = load i32, ptr addrspace(5) %"41", align 4
|
||||||
|
%"52" = inttoptr i64 %"48" to ptr
|
||||||
|
store i32 %"49", ptr %"52", align 4
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes #0 = { "amdgpu-unsafe-fp-atomics"="true" "denormal-fp-math"="preserve-sign" "denormal-fp-math-f32"="preserve-sign" "no-trapping-math"="true" "uniform-work-group-size"="true" }
|
|
@ -7,6 +7,7 @@
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
.reg .u32 %reg<10>;
|
.reg .u32 %reg<10>;
|
||||||
|
.reg .b16 %reg_16;
|
||||||
.reg .u64 %reg_64;
|
.reg .u64 %reg_64;
|
||||||
.reg .pred p;
|
.reg .pred p;
|
||||||
.reg .pred q;
|
.reg .pred q;
|
||||||
|
@ -30,4 +31,7 @@
|
||||||
|
|
||||||
// vector index - only supported by mov (maybe: ld, st, tex)
|
// vector index - only supported by mov (maybe: ld, st, tex)
|
||||||
mov.u32 %reg0, %ntid.x;
|
mov.u32 %reg0, %ntid.x;
|
||||||
|
|
||||||
|
// vector operand
|
||||||
|
mov.u32 %reg0, {0, %reg_16};
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,7 @@ test_ptx!(
|
||||||
[0x1_00_00_00_00_00_00i64]
|
[0x1_00_00_00_00_00_00i64]
|
||||||
);
|
);
|
||||||
test_ptx!(vector_extract, [1u8, 2u8, 3u8, 4u8], [3u8, 4u8, 1u8, 2u8]);
|
test_ptx!(vector_extract, [1u8, 2u8, 3u8, 4u8], [3u8, 4u8, 1u8, 2u8]);
|
||||||
|
test_ptx!(vector_operand, [0x1234u16], [0x12345678]);
|
||||||
test_ptx!(shr, [-2i32], [-1i32]);
|
test_ptx!(shr, [-2i32], [-1i32]);
|
||||||
test_ptx!(shr_oob, [-32768i16], [-1i16]);
|
test_ptx!(shr_oob, [-32768i16], [-1i16]);
|
||||||
test_ptx!(or, [1u64, 2u64], [3u64]);
|
test_ptx!(or, [1u64, 2u64], [3u64]);
|
||||||
|
|
25
ptx/src/test/spirv_run/vector_operand.ptx
Normal file
25
ptx/src/test/spirv_run/vector_operand.ptx
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
.version 6.5
|
||||||
|
.target sm_60
|
||||||
|
.address_size 64
|
||||||
|
|
||||||
|
.visible .entry vector_operand(
|
||||||
|
.param .u64 input_p,
|
||||||
|
.param .u64 output_p
|
||||||
|
)
|
||||||
|
{
|
||||||
|
.reg .u64 in_addr;
|
||||||
|
.reg .u64 out_addr;
|
||||||
|
|
||||||
|
.reg .b16 in;
|
||||||
|
.reg .b32 out;
|
||||||
|
|
||||||
|
ld.param.u64 in_addr, [input_p];
|
||||||
|
ld.param.u64 out_addr, [output_p];
|
||||||
|
|
||||||
|
ld.b16 in, [in_addr];
|
||||||
|
|
||||||
|
mov.b32 out, {0x5678, in};
|
||||||
|
|
||||||
|
st.b32 [out_addr], out;
|
||||||
|
ret;
|
||||||
|
}
|
|
@ -808,7 +808,17 @@ where
|
||||||
),
|
),
|
||||||
ParsedOperand::VecPack(vec) => ParsedOperand::VecPack(
|
ParsedOperand::VecPack(vec) => ParsedOperand::VecPack(
|
||||||
vec.into_iter()
|
vec.into_iter()
|
||||||
.map(|ident| (self)(ident, type_space, is_dst, relaxed_type_check))
|
.map(|reg_or_immediate| {
|
||||||
|
Ok(match reg_or_immediate {
|
||||||
|
RegOrImmediate::Reg(ident) => RegOrImmediate::Reg((self)(
|
||||||
|
ident,
|
||||||
|
type_space,
|
||||||
|
is_dst,
|
||||||
|
relaxed_type_check,
|
||||||
|
)?),
|
||||||
|
RegOrImmediate::Imm(imm) => RegOrImmediate::Imm(imm),
|
||||||
|
})
|
||||||
|
})
|
||||||
.collect::<Result<Vec<_>, _>>()?,
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
@ -1005,6 +1015,7 @@ impl std::fmt::Display for Type {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Type::Scalar(scalar_type) => write!(f, "{}", scalar_type),
|
Type::Scalar(scalar_type) => write!(f, "{}", scalar_type),
|
||||||
|
Type::Vector(count, scalar_type) => write!(f, ".v{}{}", count, scalar_type),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1063,6 +1074,15 @@ impl Type {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ScalarType {
|
impl ScalarType {
|
||||||
|
pub fn from_size(size: u8) -> Option<Self> {
|
||||||
|
Some(match size {
|
||||||
|
1 => ScalarType::B8,
|
||||||
|
2 => ScalarType::B16,
|
||||||
|
4 => ScalarType::B32,
|
||||||
|
16 => ScalarType::B128,
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
pub fn size_of(self) -> u8 {
|
pub fn size_of(self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
ScalarType::U8 | ScalarType::S8 | ScalarType::B8 => 1,
|
ScalarType::U8 | ScalarType::S8 | ScalarType::B8 => 1,
|
||||||
|
@ -1225,7 +1245,7 @@ pub enum ParsedOperand<Ident> {
|
||||||
RegOffset(Ident, i32),
|
RegOffset(Ident, i32),
|
||||||
Imm(ImmediateValue),
|
Imm(ImmediateValue),
|
||||||
VecMember(Ident, u8),
|
VecMember(Ident, u8),
|
||||||
VecPack(Vec<Ident>),
|
VecPack(Vec<RegOrImmediate<Ident>>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Ident> ParsedOperand<Ident> {
|
impl<Ident> ParsedOperand<Ident> {
|
||||||
|
|
|
@ -1283,12 +1283,18 @@ impl<Ident> ast::ParsedOperand<Ident> {
|
||||||
}
|
}
|
||||||
fn vector_operand<'a, 'input>(
|
fn vector_operand<'a, 'input>(
|
||||||
stream: &mut PtxParser<'a, 'input>,
|
stream: &mut PtxParser<'a, 'input>,
|
||||||
) -> PResult<Vec<&'input str>> {
|
) -> PResult<Vec<ast::RegOrImmediate<&'input str>>> {
|
||||||
let (_, r1, _, r2) = (Token::LBrace, ident, Token::Comma, ident).parse_next(stream)?;
|
let (_, r1, _, r2) = (
|
||||||
|
Token::LBrace,
|
||||||
|
reg_or_immediate,
|
||||||
|
Token::Comma,
|
||||||
|
reg_or_immediate,
|
||||||
|
)
|
||||||
|
.parse_next(stream)?;
|
||||||
// TODO: parse .v8 literals
|
// TODO: parse .v8 literals
|
||||||
dispatch! {any;
|
dispatch! {any;
|
||||||
(Token::RBrace, _) => empty.map(|_| vec![r1, r2]),
|
(Token::RBrace, _) => empty.map(|_| vec![r1, r2]),
|
||||||
(Token::Comma, _) => (ident, Token::Comma, ident, Token::RBrace).map(|(r3, _, r4, _)| vec![r1, r2, r3, r4]),
|
(Token::Comma, _) => (reg_or_immediate, Token::Comma, reg_or_immediate, Token::RBrace).map(|(r3, _, r4, _)| vec![r1, r2, r3, r4]),
|
||||||
_ => fail
|
_ => fail
|
||||||
}
|
}
|
||||||
.parse_next(stream)
|
.parse_next(stream)
|
||||||
|
@ -1325,7 +1331,7 @@ pub enum PtxError<'input> {
|
||||||
#[from]
|
#[from]
|
||||||
source: TokenError,
|
source: TokenError,
|
||||||
},
|
},
|
||||||
#[error("{0}")]
|
#[error("Context error: {0}")]
|
||||||
Parser(ContextError),
|
Parser(ContextError),
|
||||||
#[error("")]
|
#[error("")]
|
||||||
Todo,
|
Todo,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue