clang: lib/AST/ByteCode/InterpBuiltinBitCast.cpp Source File (original) (raw)

1

2

3

4

5

6

7

21

22#include

23

24using namespace clang;

26

27

28

29

30

31

32

33

34

35

36

37

40 Bits FullBitWidth, bool PackedBools)>;

41

42#define BITCAST_TYPE_SWITCH(Expr, B) \

43 do { \

44 switch (Expr) { \

45 TYPE_SWITCH_CASE(PT_Sint8, B) \

46 TYPE_SWITCH_CASE(PT_Uint8, B) \

47 TYPE_SWITCH_CASE(PT_Sint16, B) \

48 TYPE_SWITCH_CASE(PT_Uint16, B) \

49 TYPE_SWITCH_CASE(PT_Sint32, B) \

50 TYPE_SWITCH_CASE(PT_Uint32, B) \

51 TYPE_SWITCH_CASE(PT_Sint64, B) \

52 TYPE_SWITCH_CASE(PT_Uint64, B) \

53 TYPE_SWITCH_CASE(PT_IntAP, B) \

54 TYPE_SWITCH_CASE(PT_IntAPS, B) \

55 TYPE_SWITCH_CASE(PT_Bool, B) \

56 default: \

57 llvm_unreachable("Unhandled bitcast type"); \

58 } \

59 } while (0)

60

61#define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B) \

62 do { \

63 switch (Expr) { \

64 TYPE_SWITCH_CASE(PT_Sint8, B) \

65 TYPE_SWITCH_CASE(PT_Uint8, B) \

66 TYPE_SWITCH_CASE(PT_Sint16, B) \

67 TYPE_SWITCH_CASE(PT_Uint16, B) \

68 TYPE_SWITCH_CASE(PT_Sint32, B) \

69 TYPE_SWITCH_CASE(PT_Uint32, B) \

70 TYPE_SWITCH_CASE(PT_Sint64, B) \

71 TYPE_SWITCH_CASE(PT_Uint64, B) \

72 TYPE_SWITCH_CASE(PT_Bool, B) \

73 default: \

74 llvm_unreachable("Unhandled bitcast type"); \

75 } \

76 } while (0)

77

78

79

83 assert(FieldDesc);

84

85

87 Bits FullBitWidth =

89 return F(P, FieldDesc->getPrimType(), Offset, FullBitWidth,

90 false);

91 }

92

93

98

99 bool PackedBools =

101 unsigned NumElems = FieldDesc->getNumElems();

102 bool Ok = true;

103 for (unsigned I = P.getIndex(); I != NumElems; ++I) {

104 Ok = Ok && F(P.atIndex(I), ElemT, Offset, ElemSize, PackedBools);

105 Offset += PackedBools ? Bits(1) : ElemSize;

106 if (Offset >= BitsToRead)

107 break;

108 }

109 return Ok;

110 }

111

112

118 Offset += ElemSize;

119 if (Offset >= BitsToRead)

120 break;

121 }

122 return true;

123 }

124

125

130 bool Ok = true;

131

132 for (const Record::Field &Fi : R->fields()) {

133 if (Fi.isUnnamedBitField())

134 continue;

136 Bits BitOffset =

139 }

140 for (const Record::Base &B : R->bases()) {

146

147

148 if (Ok)

150 }

151

152 return Ok;

153 }

154

155 llvm_unreachable("Unhandled data type");

156}

157

162

163

164

165

166

167

168

169

170

171

172

174 bool IsToType) {

175 enum {

176 E_Union = 0,

177 E_Pointer,

178 E_MemberPointer,

179 E_Volatile,

180 E_Reference,

181 };

182 enum { C_Member, C_Base };

183

184 auto diag = [&](int Reason) -> bool {

186 S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_type)

187 << static_cast<int>(IsToType) << (Reason == E_Reference) << Reason

189 return false;

190 };

191 auto note = [&](int Construct, QualType NoteType, SourceRange NoteRange) {

192 S.Note(NoteRange.getBegin(), diag::note_constexpr_bit_cast_invalid_subtype)

193 << NoteType << Construct << T.getUnqualifiedType() << NoteRange;

194 return false;

195 };

196

197 T = T.getCanonicalType();

198

199 if (T->isUnionType())

200 return diag(E_Union);

201 if (T->isPointerType())

202 return diag(E_Pointer);

203 if (T->isMemberPointerType())

204 return diag(E_MemberPointer);

205 if (T.isVolatileQualified())

206 return diag(E_Volatile);

207

208 if (const RecordDecl *RD = T->getAsRecordDecl()) {

209 if (const auto *CXXRD = dyn_cast(RD)) {

212 return note(C_Base, BS.getType(), BS.getBeginLoc());

213 }

214 }

215 for (const FieldDecl *FD : RD->fields()) {

216 if (FD->getType()->isReferenceType())

217 return diag(E_Reference);

219 return note(C_Member, FD->getType(), FD->getSourceRange());

220 }

221 }

222

223 if (T->isArrayType() &&

225 IsToType))

226 return false;

227

228 if (const auto *VT = T->getAs<VectorType>()) {

230 QualType EltTy = VT->getElementType();

231 unsigned NElts = VT->getNumElements();

232 unsigned EltSize =

234

235 if ((NElts * EltSize) % ASTCtx.getCharWidth() != 0) {

236

237

238

239

241 S.FFDiag(E, diag::note_constexpr_bit_cast_invalid_vector)

243 return false;

244 }

245

248

249

250

252 S.FFDiag(E, diag::note_constexpr_bit_cast_unsupported_type) << EltTy;

253 return false;

254 }

255 }

256

257 return true;

258}

259

263 bool ReturnOnUninit) {

265 Endian TargetEndianness =

267

269 FromPtr, Ctx, Buffer.size(),

271 bool PackedBools) -> bool {

272 Bits BitWidth = FullBitWidth;

273

274 if (const FieldDecl *FD = P.getField(); FD && FD->isBitField())

275 BitWidth = Bits(std::min(FD->getBitWidthValue(),

276 (unsigned)FullBitWidth.getQuantity()));

277 else if (T == PT_Bool && PackedBools)

278 BitWidth = Bits(1);

279

280 if (BitWidth.isZero())

281 return true;

282

283

284 if (!P.isInitialized())

285 return true;

286

287 if (T == PT_Ptr) {

288 assert(P.getType()->isNullPtrType());

289

290

291

292 return true;

293 }

294

296 auto Buff = std::make_uniquestd::byte\[\](FullBitWidth.roundToBytes());

297

298

299

303 llvm::APFloatBase::getSizeInBits(F.getAPFloat().getSemantics()));

304 assert(NumBits.isFullByte());

305 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());

307

308

309 if (llvm::sys::IsBigEndianHost)

310 swapBytes(Buff.get(), NumBits.roundToBytes());

311

313 } else {

315

316 if (llvm::sys::IsBigEndianHost)

319 }

320

321 Buffer.pushData(Buff.get(), BitOffset, BitWidth, TargetEndianness);

322 return true;

323 });

324}

325

327 std::byte *Buff, Bits BitWidth, Bits FullBitWidth,

328 bool &HasIndeterminateBits) {

329 assert(Ptr.isLive());

331 assert(Buff);

332 assert(BitWidth <= FullBitWidth);

335

337 size_t BuffSize = FullBitWidth.roundToBytes();

339 if (CheckBitcastType(S, OpPC, DataType, false))

340 return false;

341

343 false);

345

347 Endian TargetEndianness =

349 auto B =

350 Buffer.copyBits(Bits::zero(), BitWidth, FullBitWidth, TargetEndianness);

351

352 std::memcpy(Buff, B.get(), BuffSize);

353

354 if (llvm::sys::IsBigEndianHost)

356

358}

366

369 size_t Size) {

370 assert(FromPtr.isLive());

373

376

378 return false;

379 if (CheckBitcastType(S, OpPC, FromType, false))

380 return false;

381

385 false);

386

387

388 Endian TargetEndianness =

393 bool PackedBools) -> bool {

394 QualType PtrType = P.getType();

395 if (T == PT_Float) {

396 const auto &Semantics = ASTCtx.getFloatTypeSemantics(PtrType);

397 Bits NumBits = Bits(llvm::APFloatBase::getSizeInBits(Semantics));

398 assert(NumBits.isFullByte());

399 assert(NumBits.getQuantity() <= FullBitWidth.getQuantity());

400 auto M = Buffer.copyBits(BitOffset, NumBits, FullBitWidth,

401 TargetEndianness);

402

403 if (llvm::sys::IsBigEndianHost)

404 swapBytes(M.get(), NumBits.roundToBytes());

405

406 Floating R = S.allocFloat(Semantics);

407 Floating::bitcastFromMemory(M.get(), Semantics, &R);

408 P.deref() = R;

409 P.initialize();

410 return true;

411 }

412

413 Bits BitWidth;

415 BitWidth = Bits(std::min(FD->getBitWidthValue(),

417 else if (T == PT_Bool && PackedBools)

418 BitWidth = Bits(1);

419 else

420 BitWidth = FullBitWidth;

421

422

423

426 if (!PtrType->isStdByteType() &&

427 !PtrType->isSpecificBuiltinType(BuiltinType::UChar) &&

428 !PtrType->isSpecificBuiltinType(BuiltinType::Char_U)) {

430 S.FFDiag(E, diag::note_constexpr_bit_cast_indet_dest)

431 << PtrType << S.getLangOpts().CharIsSigned

433

434 return false;

435 }

436 return true;

437 }

438

439 auto Memory = Buffer.copyBits(BitOffset, BitWidth, FullBitWidth,

440 TargetEndianness);

441 if (llvm::sys::IsBigEndianHost)

443

456 } else {

458 if (BitWidth.nonZero())

459 P.deref<T>() = T::bitcastFromMemory(Memory.get(), T::bitWidth())

460 .truncate(BitWidth.getQuantity());

461 else

462 P.deref<T>() = T::zero();

463 });

464 }

466 return true;

467 });

468

470}

471

478

479

480

481

482

483

484

490

494 Bits FullBitWidth, bool PackedBools) -> bool {

495 TYPE_SWITCH(T, { Values.push_back(P.deref()); });

496 return true;

497 });

498

499 unsigned ValueIndex = 0;

502 Bits FullBitWidth, bool PackedBools) -> bool {

503 TYPE_SWITCH(T, {

504 P.deref() = std::get(Values[ValueIndex]);

505 P.initialize();

506 });

507

508 ++ValueIndex;

509 return true;

510 });

511

512

513 assert(ValueIndex == Values.size());

514

515 return true;

516}

Defines the clang::ASTContext interface.

std::variant< Pointer, FunctionPointer, MemberPointer, FixedPoint, Integral< 8, false >, Integral< 8, true >, Integral< 16, false >, Integral< 16, true >, Integral< 32, false >, Integral< 32, true >, Integral< 64, false >, Integral< 64, true >, IntegralAP< true >, IntegralAP< false >, Boolean, Floating > PrimTypeVariant

Definition InterpBuiltinBitCast.cpp:472

#define BITCAST_TYPE_SWITCH_FIXED_SIZE(Expr, B)

Definition InterpBuiltinBitCast.cpp:61

llvm::function_ref< bool(const Pointer &P, PrimType Ty, Bits BitOffset, Bits FullBitWidth, bool PackedBools)> DataFunc

Implement __builtin_bit_cast and related operations.

Definition InterpBuiltinBitCast.cpp:38

#define BITCAST_TYPE_SWITCH(Expr, B)

Definition InterpBuiltinBitCast.cpp:42

static bool CheckBitcastType(InterpState &S, CodePtr OpPC, QualType T, bool IsToType)

Definition InterpBuiltinBitCast.cpp:173

static bool enumeratePointerFields(const Pointer &P, const Context &Ctx, Bits BitsToRead, DataFunc F)

Definition InterpBuiltinBitCast.cpp:158

static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset, Bits BitsToRead, DataFunc F)

We use this to recursively iterate over all fields and elements of a pointer and extract relevant dat...

Definition InterpBuiltinBitCast.cpp:80

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

const llvm::fltSemantics & getFloatTypeSemantics(QualType T) const

Return the APFloat 'semantics' for the specified scalar floating point type.

const ASTRecordLayout & getASTRecordLayout(const RecordDecl *D) const

Get or compute information about the layout of the specified record (struct/union/class) D,...

QualType getBaseElementType(const ArrayType *VAT) const

Return the innermost element type of an array type.

int64_t toBits(CharUnits CharSize) const

Convert a size in characters to a size in bits.

uint64_t getTypeSize(QualType T) const

Return the size of the specified (complete) type T, in bits.

CharUnits getTypeSizeInChars(QualType T) const

Return the size of the specified (complete) type T, in characters.

const TargetInfo & getTargetInfo() const

uint64_t getCharWidth() const

Return the size of the character type, in bits.

ASTRecordLayout - This class contains layout information for one RecordDecl, which is a struct/union/...

uint64_t getFieldOffset(unsigned FieldNo) const

getFieldOffset - Get the offset of the given field index, in bits.

CharUnits getBaseClassOffset(const CXXRecordDecl *Base) const

getBaseClassOffset - Get the offset, in chars, for the given base class.

Represents a base class of a C++ class.

CharUnits - This is an opaque type for sizes expressed in character units.

QuantityType getQuantity() const

getQuantity - Get the raw integer representation of this quantity.

This represents one expression.

Represents a member of a struct/union/class.

bool isBitField() const

Determines whether this field is a bitfield.

A (possibly-)qualified type.

Represents a struct/union/class.

A trivial tuple used to represent a source range.

SourceRange getSourceRange() const LLVM_READONLY

SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...

bool isLittleEndian() const

bool isPackedVectorBoolType(const ASTContext &ctx) const

bool isRealFloatingType() const

Floating point categories.

Represents a GCC generic vector type.

Wrapper around boolean types.

Pointer into the code segment.

Holds all information required to evaluate constexpr code in a module.

ASTContext & getASTContext() const

Returns the AST context.

OptPrimType classify(QualType T) const

Classifies a type.

Wrapper around fixed point types.

If a Floating is constructed from Memory, it DOES NOT OWN THAT MEMORY.

void bitcastToMemory(std::byte *Buff) const

APFloat getAPFloat() const

If an IntegralAP is constructed from Memory, it DOES NOT OWN THAT MEMORY.

static void bitcastFromMemory(const std::byte *Src, unsigned BitWidth, IntegralAP *Result)

Wrapper around numeric types.

const Expr * getExpr(CodePtr PC) const

Context & getContext() const

ASTContext & getASTContext() const override

InterpFrame * Current

The current frame.

T allocAP(unsigned BitWidth)

const LangOptions & getLangOpts() const

A pointer to a memory block, live or dead.

Pointer narrow() const

Restricts the scope of an array element pointer.

bool isInitialized() const

Checks if an object was initialized.

Pointer atIndex(uint64_t Idx) const

Offsets a pointer inside an array.

int64_t getIndex() const

Returns the index into an array.

Pointer atField(unsigned Off) const

Creates a pointer to a field.

T & deref() const

Dereferences the pointer, if it's live.

QualType getType() const

Returns the type of the innermost field.

bool isLive() const

Checks if the pointer is live.

const FieldDecl * getField() const

Returns the field information.

bool isBlockPointer() const

const Descriptor * getFieldDesc() const

Accessors for information about the innermost field.

void initialize() const

Initializes a field.

Structure/Class descriptor.

const RecordDecl * getDecl() const

Returns the underlying declaration.

llvm::iterator_range< const_base_iter > bases() const

llvm::iterator_range< const_field_iter > fields() const

OptionalDiagnostic Note(SourceLocation Loc, diag::kind DiagId)

Add a note to a prior diagnostic.

OptionalDiagnostic FFDiag(SourceLocation Loc, diag::kind DiagId=diag::note_invalid_subexpr_in_const_expr, unsigned ExtraNotes=0)

Diagnose that the evaluation could not be folded (FF => FoldFailure)

Defines the clang::TargetInfo interface.

bool readPointerToBuffer(const Context &Ctx, const Pointer &FromPtr, BitcastBuffer &Buffer, bool ReturnOnUninit)

Definition InterpBuiltinBitCast.cpp:260

bool DoBitCastPtr(InterpState &S, CodePtr OpPC, const Pointer &FromPtr, Pointer &ToPtr)

Definition InterpBuiltinBitCast.cpp:359

PrimType

Enumeration of the primitive types of the VM.

bool DoMemcpy(InterpState &S, CodePtr OpPC, const Pointer &Src, Pointer &Dest)

Copy the contents of Src into Dest.

bool DoBitCast(InterpState &S, CodePtr OpPC, const Pointer &Ptr, std::byte *Buff, Bits BitWidth, Bits FullBitWidth, bool &HasIndeterminateBits)

Definition InterpBuiltinBitCast.cpp:326

static void swapBytes(std::byte *M, size_t N)

The JSON file list parser is used to communicate input to InstallAPI.

if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))

@ Success

Annotation was successful.

const FunctionProtoType * T

U cast(CodeGen::Address addr)

Track what bits have been initialized to known values and which ones have indeterminate value.

std::unique_ptr< std::byte[]> copyBits(Bits BitOffset, Bits BitWidth, Bits FullBitWidth, Endian TargetEndianness) const

Copy BitWidth bits at offset BitOffset from the buffer.

void markInitialized(Bits Start, Bits Length)

Marks the bits in the given range as initialized.

bool rangeInitialized(Bits Offset, Bits Length) const

Bits size() const

Returns the buffer size in bits.

void pushData(const std::byte *In, Bits BitOffset, Bits BitWidth, Endian TargetEndianness)

Push BitWidth bits at BitOffset from In into the buffer.

size_t roundToBytes() const

size_t getQuantity() const

Describes a memory block created by an allocation site.

unsigned getNumElems() const

Returns the number of elements stored in the block.

bool isPrimitive() const

Checks if the descriptor is of a primitive.

QualType getElemQualType() const

bool isCompositeArray() const

Checks if the descriptor is of an array of composites.

QualType getDataType(const ASTContext &Ctx) const

bool isPrimitiveArray() const

Checks if the descriptor is of an array of primitives.

PrimType getPrimType() const

bool isRecord() const

Checks if the descriptor is of a record.

const Record *const ElemRecord

Pointer to the record, if block contains records.