summaryrefslogtreecommitdiffstats
path: root/source/slang/slang-ir-layout.h
blob: a0f144c86b440d06919d38512eb7f0273aed2caf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// slang-ir-layout.h
#pragma once

// This file provides utilities for computing and caching the *natural*
// layout of types in the IR.
//
// The natural layout is the layout a target uses for a type when it is
// stored in unconstrainted general-purpose memory (to the extent that
// the target supports unconstrained general-purpose memory).
//
// For targets like the CPU and CUDA which support a simple flat address
// space, the natural layout is the only layout used for any type.
//
// For targets like D3D DXBC/DXIL and Vulkan SPIR-V, the natural layout
// matches how a type is stored in a "structured buffer" or "shader
// storage buffer."
//

#include "slang-ir.h"

#include <limits>

namespace Slang
{
struct CompilerOptionSet;

/// Align `value` to the next multiple of `alignment`, which must be a power of two.
inline IRIntegerValue align(IRIntegerValue value, int alignment)
{
    return (value + alignment - 1) & ~IRIntegerValue(alignment - 1);
}


/// The size and alignment of an IR type.
struct IRSizeAndAlignment
{
    IRSizeAndAlignment() {}

    IRSizeAndAlignment(IRIntegerValue size, int alignment)
        : size(size), alignment(alignment)
    {
    }

    IRIntegerValue size = 0;

    // Used for an unsized array as a final struct member
    const static IRIntegerValue kIndeterminateSize = std::numeric_limits<IRIntegerValue>::min();

    int alignment = 1;

    inline IRIntegerValue getStride() { return align(size, alignment); }
};

struct IRTypeLayoutRules
{
public:
    IRTypeLayoutRuleName ruleName;

    /// This function calculates the size and alignment of the given type.
    virtual Result calcSizeAndAlignment(
        CompilerOptionSet& optionSet,
        IRType* type,
        IRSizeAndAlignment* outSizeAndAlignment);

    /// Align composite based on rule. Type is aligned assuming
    /// it is apart of a composite (array, struct, matrix, etc...)
    virtual IRSizeAndAlignment alignCompositeElement(IRSizeAndAlignment elementSize) = 0;

    /// Get alignment and size of a vector given components of vector.
    /// This alignment is not assuming this vector is a member of a struct.
    virtual IRSizeAndAlignment getVectorSizeAndAlignment(
        IRSizeAndAlignment element,
        IRIntegerValue count) = 0;

    /// Adjust the offset of an element. Handles two cases; alignmment when
    /// the previous field was a composite, and the D3D constant buffer case
    /// where an element is aligned to the next 16-byte boundary if it doesn't
    /// fit entirely within the current one.
    virtual IRIntegerValue adjustOffset(
        IRIntegerValue offset,
        IRIntegerValue elementSize,
        IRType* lastFieldType,
        IRIntegerValue lastFieldAlignment) = 0;

    static IRTypeLayoutRules* getStd430();
    static IRTypeLayoutRules* getStd140();
    static IRTypeLayoutRules* getNatural();
    static IRTypeLayoutRules* getC();
    static IRTypeLayoutRules* getConstantBuffer();
    static IRTypeLayoutRules* get(IRTypeLayoutRuleName name);
};

Result getOffset(
    CompilerOptionSet& optionSet,
    IRTypeLayoutRules* rules,
    IRStructField* field,
    IRIntegerValue* outOffset);

Result getSizeAndAlignment(
    CompilerOptionSet& optionSet,
    IRTypeLayoutRules* rules,
    IRType* type,
    IRSizeAndAlignment* outSizeAndAlignment);

/// Compute (if necessary) and return the natural size and alignment of `type`.
///
/// This operation may fail if `type` is not one that can be stored in
/// general-purpose memory for the current target. In that case the
/// type is considered to have no natural layout.
///
Result getNaturalSizeAndAlignment(
    CompilerOptionSet& optionSet,
    IRType* type,
    IRSizeAndAlignment* outSizeAndAlignment);

/// Compute (if necessary) and return the natural offset of `field`
///
/// This operation can fail if the parent type of `field` is not one
/// that can be stored in general-purpose memory. In that case, the
/// field is considered to have no natural offset.
///
Result getNaturalOffset(
    CompilerOptionSet& optionSet,
    IRStructField* field,
    IRIntegerValue* outOffset);

/// Compute (if necessary) and return the std430 size and alignment of `type`.
///
/// This operation may fail if `type` is not one that can be stored in
/// general-purpose memory for the current target. In that case the
/// type is considered to have no std430 layout.
///
Result getStd430SizeAndAlignment(
    CompilerOptionSet& optionSet,
    IRType* type,
    IRSizeAndAlignment* outSizeAndAlignment);

/// Compute (if necessary) and return the std430 offset of `field`
///
/// This operation can fail if the parent type of `field` is not one
/// that can be stored in general-purpose memory. In that case, the
/// field is considered to have no std430 offset.
///
Result getStd430Offset(
    CompilerOptionSet& optionSet,
    IRStructField* field,
    IRIntegerValue* outOffset);

} // namespace Slang