-
Notifications
You must be signed in to change notification settings - Fork 10.4k
/
Copy pathEnumPayload.h
190 lines (155 loc) · 6.77 KB
/
EnumPayload.h
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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
//===--- EnumPayload.h - Payload management for 'enum' Types ----*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#ifndef SWIFT_IRGEN_ENUMPAYLOAD_H
#define SWIFT_IRGEN_ENUMPAYLOAD_H
#include "IRGenModule.h"
#include "Explosion.h"
#include "TypeInfo.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/ADT/PointerEmbeddedInt.h"
#include "llvm/ADT/PointerUnion.h"
#include <utility>
namespace swift {
namespace irgen {
/// A description of how to represent an enum payload as a value.
/// A payload can either use a generic word-chunked representation,
/// or attempt to follow the explosion schema of one of its payload
/// types.
/// TODO: the current code only ever uses the generic word-chunked
/// representation, it might be better if it used an appropriate
/// explosion schema instead.
class EnumPayloadSchema {
// A size in bits less than 0 indicates that the payload size is
// dynamic.
const int64_t BitSize;
public:
/// Create a new schema with a dynamic size.
EnumPayloadSchema() : BitSize(-1) {}
/// Create a new schema with the given fixed size in bits.
explicit EnumPayloadSchema(unsigned bits)
: BitSize(static_cast<int64_t>(bits)) {}
/// Report whether the schema has a fixed size.
explicit operator bool() const {
return BitSize >= 0;
}
/// Invoke a functor for each element type in the schema.
template<typename TypeFn /* void(llvm::Type *schemaType) */>
void forEachType(IRGenModule &IGM, TypeFn &&fn) const {
assert(BitSize >= 0 && "payload size must not be dynamic");
// Chunk into pointer-sized integer values.
int64_t bitSize = BitSize;
int64_t pointerSize = IGM.getPointerSize().getValueInBits();
while (bitSize >= pointerSize) {
fn(IGM.SizeTy);
bitSize -= pointerSize;
}
if (bitSize > 0)
fn(llvm::IntegerType::get(IGM.getLLVMContext(), bitSize));
}
};
/// Is a switch default destination unreachable?
enum IsUnreachable_t: bool {
IsNotUnreachable = false,
IsUnreachable = true,
};
using SwitchDefaultDest
= llvm::PointerIntPair<llvm::BasicBlock*, 1, IsUnreachable_t>;
/// An enum payload value. The payload is represented as an explosion of
/// integers and pointers that together represent the bit pattern of
/// the payload.
class EnumPayload {
public:
/// A value, or the type of a zero value in the payload.
using LazyValue = llvm::PointerUnion<llvm::Value *, llvm::Type *>;
mutable SmallVector<LazyValue, 2> PayloadValues;
mutable llvm::Type *StorageType = nullptr;
EnumPayload() = default;
/// Generate a "zero" enum payload.
static EnumPayload zero(IRGenModule &IGM,
EnumPayloadSchema schema);
/// Generate an enum payload containing the given bit pattern.
static EnumPayload fromBitPattern(IRGenModule &IGM,
const APInt &bitPattern,
EnumPayloadSchema schema);
/// Insert a value into the enum payload.
///
/// The current payload value at the given offset is assumed to be zero.
/// If \p numBitsUsedInValue is non-negative denotes the actual number of bits
/// that need storing in \p value otherwise the full bit-width of \p value
/// will be stored.
void insertValue(IRGenModule &IGM,
IRBuilder &builder,
llvm::Value *value, unsigned bitOffset);
/// Extract a value from the enum payload.
llvm::Value *extractValue(IRGenFunction &IGF,
llvm::Type *type, unsigned bitOffset) const;
/// Take an enum payload out of an explosion.
static EnumPayload fromExplosion(IRGenModule &IGM,
Explosion &in,
EnumPayloadSchema schema);
/// Add the payload to an explosion.
void explode(IRGenModule &IGM, Explosion &out) const;
/// Pack into another enum payload.
void packIntoEnumPayload(IRGenModule &IGM,
IRBuilder &builder,
EnumPayload &dest,
unsigned bitOffset) const;
/// Unpack from another enum payload.
static EnumPayload unpackFromEnumPayload(IRGenFunction &IGF,
const EnumPayload &src,
unsigned bitOffset,
EnumPayloadSchema schema);
/// Load an enum payload from memory.
static EnumPayload load(IRGenFunction &IGF, Address address,
EnumPayloadSchema schema);
/// Store an enum payload to memory.
void store(IRGenFunction &IGF, Address address) const;
/// Emit a switch over specific bit patterns for the payload.
/// The value will be tested as if AND-ed against the given mask.
void emitSwitch(IRGenFunction &IGF,
const APInt &mask,
ArrayRef<std::pair<APInt, llvm::BasicBlock*>> cases,
SwitchDefaultDest dflt) const;
/// Emit an equality comparison operation that payload & mask == value.
llvm::Value *emitCompare(IRGenFunction &IGF,
const APInt &mask,
const APInt &value) const;
/// Apply an AND mask to the payload.
void emitApplyAndMask(IRGenFunction &IGF, const APInt &mask);
/// Apply an OR mask to the payload.
void emitApplyOrMask(IRGenModule &IGM,
IRBuilder &builder, const APInt &mask);
/// Apply an OR mask to the payload.
void emitApplyOrMask(IRGenFunction &IGF, EnumPayload mask);
/// Scatter the bits in value to the bit positions indicated by the
/// mask. The new bits are added using OR, so an emitApplyAndMask
/// call should be used first if existing bits need to be cleared.
void emitScatterBits(IRGenModule &IGM,
IRBuilder &builder,
const APInt &mask,
llvm::Value *value);
/// Gather bits from an enum payload based on a spare bit mask.
llvm::Value *emitGatherSpareBits(IRGenFunction &IGF,
const SpareBitVector &spareBits,
unsigned firstBitOffset,
unsigned bitWidth) const;
void print(llvm::raw_ostream &OS);
void dump();
private:
/// Calculate the total number of bits this payload requires.
/// This will always be a multiple of 8.
unsigned getAllocSizeInBits(const llvm::DataLayout &DL) const;
};
}
}
#endif