@@ -4,12 +4,13 @@ use crate::spirv_type::SpirvType;
4
4
use crate :: symbols:: Symbols ;
5
5
use crate :: target:: SpirvTarget ;
6
6
use crate :: target_feature:: TargetFeature ;
7
- use rspirv:: dr:: { Block , Builder , Module , Operand } ;
7
+ use rspirv:: dr:: { Block , Builder , Instruction , Module , Operand } ;
8
8
use rspirv:: spirv:: {
9
9
AddressingModel , Capability , MemoryModel , Op , SourceLanguage , StorageClass , Word ,
10
10
} ;
11
11
use rspirv:: { binary:: Assemble , binary:: Disassemble } ;
12
12
use rustc_arena:: DroplessArena ;
13
+ use rustc_codegen_ssa:: traits:: ConstMethods as _;
13
14
use rustc_data_structures:: fx:: { FxHashMap , FxHashSet } ;
14
15
use rustc_data_structures:: sync:: Lrc ;
15
16
use rustc_middle:: bug;
@@ -18,6 +19,7 @@ use rustc_middle::ty::TyCtxt;
18
19
use rustc_span:: source_map:: SourceMap ;
19
20
use rustc_span:: symbol:: Symbol ;
20
21
use rustc_span:: { FileName , FileNameDisplayPreference , SourceFile , Span , DUMMY_SP } ;
22
+ use rustc_target:: abi:: Size ;
21
23
use std:: assert_matches:: assert_matches;
22
24
use std:: cell:: { RefCell , RefMut } ;
23
25
use std:: hash:: { Hash , Hasher } ;
@@ -221,13 +223,8 @@ impl SpirvValueExt for Word {
221
223
222
224
#[ derive( Debug , Copy , Clone , PartialEq , Eq , Hash ) ]
223
225
pub enum SpirvConst < ' a , ' tcx > {
224
- U32 ( u32 ) ,
225
- U64 ( u64 ) ,
226
- /// f32 isn't hash, so store bits
227
- F32 ( u32 ) ,
228
- /// f64 isn't hash, so store bits
229
- F64 ( u64 ) ,
230
- Bool ( bool ) ,
226
+ /// Constants of boolean, integer or floating-point type (up to 128-bit).
227
+ Scalar ( u128 ) ,
231
228
232
229
Null ,
233
230
Undef ,
@@ -273,11 +270,7 @@ impl<'tcx> SpirvConst<'_, 'tcx> {
273
270
274
271
match self {
275
272
// FIXME(eddyb) these are all noop cases, could they be automated?
276
- SpirvConst :: U32 ( v) => SpirvConst :: U32 ( v) ,
277
- SpirvConst :: U64 ( v) => SpirvConst :: U64 ( v) ,
278
- SpirvConst :: F32 ( v) => SpirvConst :: F32 ( v) ,
279
- SpirvConst :: F64 ( v) => SpirvConst :: F64 ( v) ,
280
- SpirvConst :: Bool ( v) => SpirvConst :: Bool ( v) ,
273
+ SpirvConst :: Scalar ( v) => SpirvConst :: Scalar ( v) ,
281
274
SpirvConst :: Null => SpirvConst :: Null ,
282
275
SpirvConst :: Undef => SpirvConst :: Undef ,
283
276
SpirvConst :: ZombieUndefForFnAddr => SpirvConst :: ZombieUndefForFnAddr ,
@@ -570,8 +563,26 @@ impl<'tcx> BuilderSpirv<'tcx> {
570
563
val : SpirvConst < ' _ , ' tcx > ,
571
564
cx : & CodegenCx < ' tcx > ,
572
565
) -> SpirvValue {
566
+ let scalar_ty = match val {
567
+ SpirvConst :: Scalar ( _) => Some ( cx. lookup_type ( ty) ) ,
568
+ _ => None ,
569
+ } ;
570
+
571
+ // HACK(eddyb) this is done so late (just before interning `val`) to
572
+ // minimize any potential misuse from direct `def_constant` calls.
573
+ let val = match ( val, scalar_ty) {
574
+ ( SpirvConst :: Scalar ( val) , Some ( SpirvType :: Integer ( bits, signed) ) ) => {
575
+ let size = Size :: from_bits ( bits) ;
576
+ SpirvConst :: Scalar ( if signed {
577
+ size. sign_extend ( val)
578
+ } else {
579
+ size. truncate ( val)
580
+ } )
581
+ }
582
+ _ => val,
583
+ } ;
584
+
573
585
let val_with_type = WithType { ty, val } ;
574
- let mut builder = self . builder ( BuilderCursor :: default ( ) ) ;
575
586
if let Some ( entry) = self . const_to_id . borrow ( ) . get ( & val_with_type) {
576
587
// FIXME(eddyb) deduplicate this `if`-`else` and its other copies.
577
588
let kind = if entry. legal . is_ok ( ) {
@@ -582,16 +593,99 @@ impl<'tcx> BuilderSpirv<'tcx> {
582
593
return SpirvValue { kind, ty } ;
583
594
}
584
595
let val = val_with_type. val ;
596
+
597
+ // FIXME(eddyb) make this an extension method on `rspirv::dr::Builder`?
598
+ let const_op = |builder : & mut Builder , op, lhs, maybe_rhs : Option < _ > | {
599
+ // HACK(eddyb) remove after `OpSpecConstantOp` support gets added to SPIR-T.
600
+ let spirt_has_const_op = false ;
601
+
602
+ if !spirt_has_const_op {
603
+ let zombie = builder. undef ( ty, None ) ;
604
+ cx. zombie_with_span (
605
+ zombie,
606
+ DUMMY_SP ,
607
+ & format ! ( "unsupported constant of type `{}`" , cx. debug_type( ty) ) ,
608
+ ) ;
609
+ return zombie;
610
+ }
611
+
612
+ let id = builder. id ( ) ;
613
+ builder
614
+ . module_mut ( )
615
+ . types_global_values
616
+ . push ( Instruction :: new (
617
+ Op :: SpecConstantOp ,
618
+ Some ( ty) ,
619
+ Some ( id) ,
620
+ [
621
+ Operand :: LiteralSpecConstantOpInteger ( op) ,
622
+ Operand :: IdRef ( lhs) ,
623
+ ]
624
+ . into_iter ( )
625
+ . chain ( maybe_rhs. map ( Operand :: IdRef ) )
626
+ . collect ( ) ,
627
+ ) ) ;
628
+ id
629
+ } ;
630
+
631
+ let mut builder = self . builder ( BuilderCursor :: default ( ) ) ;
585
632
let id = match val {
586
- SpirvConst :: U32 ( v) | SpirvConst :: F32 ( v) => builder. constant_bit32 ( ty, v) ,
587
- SpirvConst :: U64 ( v) | SpirvConst :: F64 ( v) => builder. constant_bit64 ( ty, v) ,
588
- SpirvConst :: Bool ( v) => {
589
- if v {
590
- builder. constant_true ( ty)
591
- } else {
592
- builder. constant_false ( ty)
633
+ SpirvConst :: Scalar ( v) => match scalar_ty. unwrap ( ) {
634
+ SpirvType :: Integer ( ..=32 , _) | SpirvType :: Float ( ..=32 ) => {
635
+ builder. constant_bit32 ( ty, v as u32 )
593
636
}
594
- }
637
+ SpirvType :: Integer ( 64 , _) | SpirvType :: Float ( 64 ) => {
638
+ builder. constant_bit64 ( ty, v as u64 )
639
+ }
640
+ SpirvType :: Integer ( 128 , false ) => {
641
+ // HACK(eddyb) avoid borrow conflicts.
642
+ drop ( builder) ;
643
+
644
+ let const_64_u32_id = cx. const_u32 ( 64 ) . def_cx ( cx) ;
645
+ let [ lo_id, hi_id] =
646
+ [ v as u64 , ( v >> 64 ) as u64 ] . map ( |half| cx. const_u64 ( half) . def_cx ( cx) ) ;
647
+
648
+ builder = self . builder ( BuilderCursor :: default ( ) ) ;
649
+ let mut const_op =
650
+ |op, lhs, maybe_rhs| const_op ( & mut builder, op, lhs, maybe_rhs) ;
651
+ let [ lo_u128_id, hi_shifted_u128_id] =
652
+ [ ( lo_id, None ) , ( hi_id, Some ( const_64_u32_id) ) ] . map (
653
+ |( half_u64_id, shift) | {
654
+ let mut half_u128_id = const_op ( Op :: UConvert , half_u64_id, None ) ;
655
+ if let Some ( shift_amount_id) = shift {
656
+ half_u128_id = const_op (
657
+ Op :: ShiftLeftLogical ,
658
+ half_u128_id,
659
+ Some ( shift_amount_id) ,
660
+ ) ;
661
+ }
662
+ half_u128_id
663
+ } ,
664
+ ) ;
665
+ const_op ( Op :: BitwiseOr , lo_u128_id, Some ( hi_shifted_u128_id) )
666
+ }
667
+ SpirvType :: Integer ( 128 , true ) | SpirvType :: Float ( 128 ) => {
668
+ // HACK(eddyb) avoid borrow conflicts.
669
+ drop ( builder) ;
670
+
671
+ let v_u128_id = cx. const_u128 ( v) . def_cx ( cx) ;
672
+
673
+ builder = self . builder ( BuilderCursor :: default ( ) ) ;
674
+ const_op ( & mut builder, Op :: Bitcast , v_u128_id, None )
675
+ }
676
+ SpirvType :: Bool => match v {
677
+ 0 => builder. constant_false ( ty) ,
678
+ 1 => builder. constant_true ( ty) ,
679
+ _ => cx
680
+ . tcx
681
+ . dcx ( )
682
+ . fatal ( format ! ( "invalid constant value for bool: {v}" ) ) ,
683
+ } ,
684
+ other => cx. tcx . dcx ( ) . fatal ( format ! (
685
+ "SpirvConst::Scalar does not support type {}" ,
686
+ other. debug( ty, cx)
687
+ ) ) ,
688
+ } ,
595
689
596
690
SpirvConst :: Null => builder. constant_null ( ty) ,
597
691
SpirvConst :: Undef
@@ -606,11 +700,7 @@ impl<'tcx> BuilderSpirv<'tcx> {
606
700
} ;
607
701
#[ allow( clippy:: match_same_arms) ]
608
702
let legal = match val {
609
- SpirvConst :: U32 ( _)
610
- | SpirvConst :: U64 ( _)
611
- | SpirvConst :: F32 ( _)
612
- | SpirvConst :: F64 ( _)
613
- | SpirvConst :: Bool ( _) => Ok ( ( ) ) ,
703
+ SpirvConst :: Scalar ( _) => Ok ( ( ) ) ,
614
704
615
705
SpirvConst :: Null => {
616
706
// FIXME(eddyb) check that the type supports `OpConstantNull`.
@@ -712,10 +802,9 @@ impl<'tcx> BuilderSpirv<'tcx> {
712
802
}
713
803
}
714
804
715
- pub fn lookup_const_u64 ( & self , def : SpirvValue ) -> Option < u64 > {
805
+ pub fn lookup_const_scalar ( & self , def : SpirvValue ) -> Option < u128 > {
716
806
match self . lookup_const ( def) ? {
717
- SpirvConst :: U32 ( v) => Some ( v as u64 ) ,
718
- SpirvConst :: U64 ( v) => Some ( v) ,
807
+ SpirvConst :: Scalar ( v) => Some ( v) ,
719
808
_ => None ,
720
809
}
721
810
}
0 commit comments