Skip to content

Commit 557a510

Browse files
SC llvm teamSC llvm team
SC llvm team
authored and
SC llvm team
committed
Merged main:207e485f4b7e into amd-gfx:0bafa7d8639b
Local branch amd-gfx 0bafa7d Merged main:bc87a537d9b8 into amd-gfx:f699e122cfa0 Remote branch main 207e485 [VPlan] Track VectorPH during skeleton creation. (NFC)
2 parents 0bafa7d + 207e485 commit 557a510

File tree

23 files changed

+1496
-135
lines changed

23 files changed

+1496
-135
lines changed

clang/include/clang/Basic/arm_immcheck_incl.td

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,20 @@ class ImmCheckType<int val> {
22
int Value = val;
33
}
44

5-
// These must be kept in sync with the flags in include/clang/Basic/TargetBuiltins.h
5+
6+
// For SVE, container_size refers to the width of a vector segment (128b).
7+
// For NEON, container_size refers to the vector width (64b or 128b).
68
def ImmCheck0_31 : ImmCheckType<0>; // 0..31 (used for e.g. predicate patterns)
79
def ImmCheck1_16 : ImmCheckType<1>; // 1..16
810
def ImmCheckExtract : ImmCheckType<2>; // 0..(2048/sizeinbits(elt) - 1)
911
def ImmCheckShiftRight : ImmCheckType<3>; // 1..sizeinbits(elt)
1012
def ImmCheckShiftRightNarrow : ImmCheckType<4>; // 1..sizeinbits(elt)/2
1113
def ImmCheckShiftLeft : ImmCheckType<5>; // 0..(sizeinbits(elt) - 1)
1214
def ImmCheck0_7 : ImmCheckType<6>; // 0..7
13-
def ImmCheckLaneIndex : ImmCheckType<7>; // 0..(sizeinbits(vec)/(sizeinbits(elt)) - 1)
15+
def ImmCheckLaneIndex : ImmCheckType<7>; // 0..(container_size/(sizeinbits(elt)) - 1)
1416
def ImmCheckCvt : ImmCheckType<8>; // 1..sizeinbits(elt) (same as ShiftRight)
15-
def ImmCheckLaneIndexCompRotate : ImmCheckType<9>; // 0..(sizeinbits(vec)/(2*sizeinbits(elt)) - 1)
16-
def ImmCheckLaneIndexDot : ImmCheckType<10>; // 0..(sizeinbits(vec)/(4*sizeinbits(elt)) - 1)
17+
def ImmCheckLaneIndexCompRotate : ImmCheckType<9>; // 0..(container_size/(2*sizeinbits(elt)) - 1)
18+
def ImmCheckLaneIndexDot : ImmCheckType<10>; // 0..(container_size/(4*sizeinbits(elt)) - 1)
1719
def ImmCheckComplexRot90_270 : ImmCheckType<11>; // [90,270]
1820
def ImmCheckComplexRotAll90 : ImmCheckType<12>; // [0, 90, 180,270]
1921
def ImmCheck0_13 : ImmCheckType<13>; // 0..13

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1863,11 +1863,17 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18631863
return false;
18641864
}
18651865

1866+
// Can't read from dummy pointers.
1867+
if (DestPtr.isDummy() || SrcPtr.isDummy())
1868+
return false;
1869+
18661870
QualType DestElemType;
18671871
size_t RemainingDestElems;
18681872
if (DestPtr.getFieldDesc()->isArray()) {
18691873
DestElemType = DestPtr.getFieldDesc()->getElemQualType();
1870-
RemainingDestElems = (DestPtr.getNumElems() - DestPtr.getIndex());
1874+
RemainingDestElems = DestPtr.isUnknownSizeArray()
1875+
? 0
1876+
: (DestPtr.getNumElems() - DestPtr.getIndex());
18711877
} else {
18721878
DestElemType = DestPtr.getType();
18731879
RemainingDestElems = 1;
@@ -1886,7 +1892,9 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18861892
size_t RemainingSrcElems;
18871893
if (SrcPtr.getFieldDesc()->isArray()) {
18881894
SrcElemType = SrcPtr.getFieldDesc()->getElemQualType();
1889-
RemainingSrcElems = (SrcPtr.getNumElems() - SrcPtr.getIndex());
1895+
RemainingSrcElems = SrcPtr.isUnknownSizeArray()
1896+
? 0
1897+
: (SrcPtr.getNumElems() - SrcPtr.getIndex());
18901898
} else {
18911899
SrcElemType = SrcPtr.getType();
18921900
RemainingSrcElems = 1;
@@ -1925,9 +1933,6 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
19251933
}
19261934
}
19271935

1928-
// As a last resort, reject dummy pointers.
1929-
if (DestPtr.isDummy() || SrcPtr.isDummy())
1930-
return false;
19311936
assert(Size.getZExtValue() % DestElemSize == 0);
19321937
if (!DoMemcpy(S, OpPC, SrcPtr, DestPtr, Bytes(Size.getZExtValue()).toBits()))
19331938
return false;

clang/lib/AST/ByteCode/InterpBuiltinBitCast.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ static bool enumerateData(const Pointer &P, const Context &Ctx, Bits Offset,
110110
if (FieldDesc->isCompositeArray()) {
111111
QualType ElemType = FieldDesc->getElemQualType();
112112
Bits ElemSize = Bits(Ctx.getASTContext().getTypeSize(ElemType));
113-
for (unsigned I = 0; I != FieldDesc->getNumElems(); ++I) {
113+
for (unsigned I = P.getIndex(); I != FieldDesc->getNumElems(); ++I) {
114114
enumerateData(P.atIndex(I).narrow(), Ctx, Offset, BitsToRead, F);
115115
Offset += ElemSize;
116116
if (Offset >= BitsToRead)

clang/lib/Sema/SemaARM.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ enum ArmSMEState : unsigned {
372372

373373
bool SemaARM::CheckImmediateArg(CallExpr *TheCall, unsigned CheckTy,
374374
unsigned ArgIdx, unsigned EltBitWidth,
375-
unsigned VecBitWidth) {
375+
unsigned ContainerBitWidth) {
376376
// Function that checks whether the operand (ArgIdx) is an immediate
377377
// that is one of a given set of values.
378378
auto CheckImmediateInSet = [&](std::initializer_list<int64_t> Set,
@@ -445,17 +445,17 @@ bool SemaARM::CheckImmediateArg(CallExpr *TheCall, unsigned CheckTy,
445445
break;
446446
case ImmCheckType::ImmCheckLaneIndex:
447447
if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0,
448-
(VecBitWidth / EltBitWidth) - 1))
448+
(ContainerBitWidth / EltBitWidth) - 1))
449449
return true;
450450
break;
451451
case ImmCheckType::ImmCheckLaneIndexCompRotate:
452-
if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0,
453-
(VecBitWidth / (2 * EltBitWidth)) - 1))
452+
if (SemaRef.BuiltinConstantArgRange(
453+
TheCall, ArgIdx, 0, (ContainerBitWidth / (2 * EltBitWidth)) - 1))
454454
return true;
455455
break;
456456
case ImmCheckType::ImmCheckLaneIndexDot:
457-
if (SemaRef.BuiltinConstantArgRange(TheCall, ArgIdx, 0,
458-
(VecBitWidth / (4 * EltBitWidth)) - 1))
457+
if (SemaRef.BuiltinConstantArgRange(
458+
TheCall, ArgIdx, 0, (ContainerBitWidth / (4 * EltBitWidth)) - 1))
459459
return true;
460460
break;
461461
case ImmCheckType::ImmCheckComplexRot90_270:
@@ -515,13 +515,13 @@ bool SemaARM::PerformNeonImmChecks(
515515
bool HasError = false;
516516

517517
for (const auto &I : ImmChecks) {
518-
auto [ArgIdx, CheckTy, ElementSizeInBits, VecSizeInBits] = I;
518+
auto [ArgIdx, CheckTy, ElementBitWidth, VecBitWidth] = I;
519519

520520
if (OverloadType >= 0)
521-
ElementSizeInBits = NeonTypeFlags(OverloadType).getEltSizeInBits();
521+
ElementBitWidth = NeonTypeFlags(OverloadType).getEltSizeInBits();
522522

523-
HasError |= CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementSizeInBits,
524-
VecSizeInBits);
523+
HasError |= CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementBitWidth,
524+
VecBitWidth);
525525
}
526526

527527
return HasError;
@@ -532,9 +532,9 @@ bool SemaARM::PerformSVEImmChecks(
532532
bool HasError = false;
533533

534534
for (const auto &I : ImmChecks) {
535-
auto [ArgIdx, CheckTy, ElementSizeInBits] = I;
535+
auto [ArgIdx, CheckTy, ElementBitWidth] = I;
536536
HasError |=
537-
CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementSizeInBits, 128);
537+
CheckImmediateArg(TheCall, CheckTy, ArgIdx, ElementBitWidth, 128);
538538
}
539539

540540
return HasError;

clang/test/AST/ByteCode/builtin-functions.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1253,6 +1253,25 @@ namespace BuiltinMemcpy {
12531253
static_assert(test_memmove(2, 0, 12) == 4234); // both-error {{constant}} \
12541254
// both-note {{in call}}
12551255
#endif
1256+
1257+
struct Trivial { char k; short s; constexpr bool ok() { return k == 3 && s == 4; } };
1258+
constexpr bool test_trivial() {
1259+
Trivial arr[3] = {{1, 2}, {3, 4}, {5, 6}};
1260+
__builtin_memcpy(arr, arr+1, sizeof(Trivial));
1261+
__builtin_memmove(arr+1, arr, 2 * sizeof(Trivial));
1262+
1263+
return arr[0].ok() && arr[1].ok() && arr[2].ok();
1264+
}
1265+
static_assert(test_trivial());
1266+
1267+
// Check that an incomplete array is rejected.
1268+
constexpr int test_incomplete_array_type() { // both-error {{never produces a constant}}
1269+
extern int arr[];
1270+
__builtin_memmove(arr, arr, 4 * sizeof(arr[0]));
1271+
// both-note@-1 2{{'memmove' not supported: source is not a contiguous array of at least 4 elements of type 'int'}}
1272+
return arr[0] * 1000 + arr[1] * 100 + arr[2] * 10 + arr[3];
1273+
}
1274+
static_assert(test_incomplete_array_type() == 1234); // both-error {{constant}} both-note {{in call}}
12561275
}
12571276

12581277
namespace Memcmp {

clang/test/CodeGen/builtin-memfns.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm < %s| FileCheck %s
2+
// RUN: %clang_cc1 -triple i386-pc-linux-gnu -emit-llvm -fexperimental-new-constant-interpreter < %s| FileCheck %s
23

34
typedef __WCHAR_TYPE__ wchar_t;
45
typedef __SIZE_TYPE__ size_t;

flang/lib/Optimizer/Transforms/DebugTypeGenerator.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ static bool canCacheThisType(mlir::LLVM::DICompositeTypeAttr comTy) {
325325
std::pair<std::uint64_t, unsigned short>
326326
DebugTypeGenerator::getFieldSizeAndAlign(mlir::Type fieldTy) {
327327
mlir::Type llvmTy;
328-
if (auto boxTy = mlir::dyn_cast_or_null<fir::BaseBoxType>(fieldTy))
328+
if (auto boxTy = mlir::dyn_cast_if_present<fir::BaseBoxType>(fieldTy))
329329
llvmTy = llvmTypeConverter.convertBoxTypeAsStruct(boxTy, getBoxRank(boxTy));
330330
else
331331
llvmTy = llvmTypeConverter.convertType(fieldTy);
@@ -371,7 +371,7 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertRecordType(
371371
std::optional<llvm::ArrayRef<int64_t>> lowerBounds =
372372
fir::getComponentLowerBoundsIfNonDefault(Ty, fieldName, module,
373373
symbolTable);
374-
auto seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(fieldTy);
374+
auto seqTy = mlir::dyn_cast_if_present<fir::SequenceType>(fieldTy);
375375

376376
// For members of the derived types, the information about the shift in
377377
// lower bounds is not part of the declOp but has to be extracted from the
@@ -622,10 +622,10 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertPointerLikeType(
622622
// Arrays and character need different treatment because DWARF have special
623623
// constructs for them to get the location from the descriptor. Rest of
624624
// types are handled like pointer to underlying type.
625-
if (auto seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(elTy))
625+
if (auto seqTy = mlir::dyn_cast_if_present<fir::SequenceType>(elTy))
626626
return convertBoxedSequenceType(seqTy, fileAttr, scope, declOp,
627627
genAllocated, genAssociated);
628-
if (auto charTy = mlir::dyn_cast_or_null<fir::CharacterType>(elTy))
628+
if (auto charTy = mlir::dyn_cast_if_present<fir::CharacterType>(elTy))
629629
return convertCharacterType(charTy, fileAttr, scope, declOp,
630630
/*hasDescriptor=*/true);
631631

@@ -638,7 +638,7 @@ mlir::LLVM::DITypeAttr DebugTypeGenerator::convertPointerLikeType(
638638

639639
return mlir::LLVM::DIDerivedTypeAttr::get(
640640
context, llvm::dwarf::DW_TAG_pointer_type,
641-
mlir::StringAttr::get(context, ""), elTyAttr, ptrSize,
641+
mlir::StringAttr::get(context, ""), elTyAttr, /*sizeInBits=*/ptrSize * 8,
642642
/*alignInBits=*/0, /*offset=*/0,
643643
/*optional<address space>=*/std::nullopt, /*extra data=*/nullptr);
644644
}
@@ -654,22 +654,22 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr,
654654
} else if (mlir::isa<mlir::FloatType>(Ty)) {
655655
return genBasicType(context, mlir::StringAttr::get(context, "real"),
656656
Ty.getIntOrFloatBitWidth(), llvm::dwarf::DW_ATE_float);
657-
} else if (auto logTy = mlir::dyn_cast_or_null<fir::LogicalType>(Ty)) {
657+
} else if (auto logTy = mlir::dyn_cast_if_present<fir::LogicalType>(Ty)) {
658658
return genBasicType(context,
659659
mlir::StringAttr::get(context, logTy.getMnemonic()),
660660
kindMapping.getLogicalBitsize(logTy.getFKind()),
661661
llvm::dwarf::DW_ATE_boolean);
662-
} else if (auto cplxTy = mlir::dyn_cast_or_null<mlir::ComplexType>(Ty)) {
662+
} else if (auto cplxTy = mlir::dyn_cast_if_present<mlir::ComplexType>(Ty)) {
663663
auto floatTy = mlir::cast<mlir::FloatType>(cplxTy.getElementType());
664664
unsigned bitWidth = floatTy.getWidth();
665665
return genBasicType(context, mlir::StringAttr::get(context, "complex"),
666666
bitWidth * 2, llvm::dwarf::DW_ATE_complex_float);
667-
} else if (auto seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(Ty)) {
667+
} else if (auto seqTy = mlir::dyn_cast_if_present<fir::SequenceType>(Ty)) {
668668
return convertSequenceType(seqTy, fileAttr, scope, declOp);
669-
} else if (auto charTy = mlir::dyn_cast_or_null<fir::CharacterType>(Ty)) {
669+
} else if (auto charTy = mlir::dyn_cast_if_present<fir::CharacterType>(Ty)) {
670670
return convertCharacterType(charTy, fileAttr, scope, declOp,
671671
/*hasDescriptor=*/false);
672-
} else if (auto recTy = mlir::dyn_cast_or_null<fir::RecordType>(Ty)) {
672+
} else if (auto recTy = mlir::dyn_cast_if_present<fir::RecordType>(Ty)) {
673673
return convertRecordType(recTy, fileAttr, scope, declOp);
674674
} else if (auto tupleTy = mlir::dyn_cast_if_present<mlir::TupleType>(Ty)) {
675675
return convertTupleType(tupleTy, fileAttr, scope, declOp);
@@ -678,22 +678,22 @@ DebugTypeGenerator::convertType(mlir::Type Ty, mlir::LLVM::DIFileAttr fileAttr,
678678
return convertPointerLikeType(elTy, fileAttr, scope, declOp,
679679
/*genAllocated=*/false,
680680
/*genAssociated=*/false);
681-
} else if (auto vecTy = mlir::dyn_cast_or_null<fir::VectorType>(Ty)) {
681+
} else if (auto vecTy = mlir::dyn_cast_if_present<fir::VectorType>(Ty)) {
682682
return convertVectorType(vecTy, fileAttr, scope, declOp);
683683
} else if (mlir::isa<mlir::IndexType>(Ty)) {
684684
return genBasicType(context, mlir::StringAttr::get(context, "integer"),
685685
llvmTypeConverter.getIndexTypeBitwidth(),
686686
llvm::dwarf::DW_ATE_signed);
687-
} else if (auto boxTy = mlir::dyn_cast_or_null<fir::BaseBoxType>(Ty)) {
687+
} else if (auto boxTy = mlir::dyn_cast_if_present<fir::BaseBoxType>(Ty)) {
688688
auto elTy = boxTy.getEleTy();
689-
if (auto seqTy = mlir::dyn_cast_or_null<fir::SequenceType>(elTy))
689+
if (auto seqTy = mlir::dyn_cast_if_present<fir::SequenceType>(elTy))
690690
return convertBoxedSequenceType(seqTy, fileAttr, scope, declOp, false,
691691
false);
692-
if (auto heapTy = mlir::dyn_cast_or_null<fir::HeapType>(elTy))
692+
if (auto heapTy = mlir::dyn_cast_if_present<fir::HeapType>(elTy))
693693
return convertPointerLikeType(heapTy.getElementType(), fileAttr, scope,
694694
declOp, /*genAllocated=*/true,
695695
/*genAssociated=*/false);
696-
if (auto ptrTy = mlir::dyn_cast_or_null<fir::PointerType>(elTy))
696+
if (auto ptrTy = mlir::dyn_cast_if_present<fir::PointerType>(elTy))
697697
return convertPointerLikeType(ptrTy.getElementType(), fileAttr, scope,
698698
declOp, /*genAllocated=*/false,
699699
/*genAssociated=*/true);

lld/COFF/SymbolTable.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,15 @@ void SymbolTable::initializeLoadConfig() {
536536
auto sym =
537537
dyn_cast_or_null<DefinedRegular>(findUnderscore("_load_config_used"));
538538
if (!sym) {
539+
if (isEC()) {
540+
Warn(ctx) << "EC version of '_load_config_used' is missing";
541+
return;
542+
}
543+
if (ctx.hybridSymtab) {
544+
Warn(ctx) << "native version of '_load_config_used' is missing for "
545+
"ARM64X target";
546+
return;
547+
}
539548
if (ctx.config.guardCF != GuardCFLevel::Off)
540549
Warn(ctx)
541550
<< "Control Flow Guard is enabled but '_load_config_used' is missing";

lld/test/COFF/arm64x-loadconfig.s

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,19 @@
88
// RUN: llvm-mc -filetype=obj -triple=aarch64-windows loadconfig-short.s -o loadconfig-short.obj
99
// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows loadconfig-short.s -o loadconfig-short-arm64ec.obj
1010

11-
// RUN: lld-link -machine:arm64x -out:out.dll -dll -noentry loadconfig.obj test.obj
11+
// RUN: lld-link -machine:arm64x -out:out-warn.dll -dll -noentry test.obj \
12+
// RUN: 2>&1 | FileCheck --check-prefixes=WARN-LOADCFG,WARN-EC-LOADCFG %s
13+
// WARN-LOADCFG: lld-link: warning: native version of '_load_config_used' is missing for ARM64X target
14+
// WARN-EC-LOADCFG: lld-link: warning: EC version of '_load_config_used' is missing
15+
16+
// RUN: lld-link -machine:arm64x -out:out-nonative.dll -dll -noentry loadconfig-ec.obj chpe.obj \
17+
// RUN: 2>&1 | FileCheck --check-prefixes=WARN-LOADCFG --implicit-check-not EC %s
18+
19+
// RUN: lld-link -machine:arm64ec -out:out-ec.dll -dll -noentry chpe.obj \
20+
// RUN: 2>&1 | FileCheck --check-prefixes=WARN-EC-LOADCFG --implicit-check-not native %s
21+
22+
// RUN: lld-link -machine:arm64x -out:out.dll -dll -noentry loadconfig.obj test.obj \
23+
// RUN: 2>&1 | FileCheck --check-prefixes=WARN-EC-LOADCFG --implicit-check-not native %s
1224

1325
// RUN: llvm-readobj --coff-load-config out.dll | FileCheck --check-prefix=DYNRELOCS %s
1426
// DYNRELOCS: DynamicValueRelocTableOffset: 0xC

llvm/include/llvm/Config/llvm-config.h.cmake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
/* Indicate that this is LLVM compiled from the amd-gfx branch. */
1818
#define LLVM_HAVE_BRANCH_AMD_GFX
19-
#define LLVM_MAIN_REVISION 522588
19+
#define LLVM_MAIN_REVISION 522603
2020

2121
/* Define if LLVM_ENABLE_DUMP is enabled */
2222
#cmakedefine LLVM_ENABLE_DUMP

llvm/include/llvm/ExecutionEngine/JITLink/loongarch.h

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,50 @@ enum EdgeKind_loongarch : Edge::Kind {
4141
///
4242
Pointer32,
4343

44+
/// A 16-bit PC-relative branch.
45+
///
46+
/// Represents a PC-relative branch to a target within +/-128Kb. The target
47+
/// must be 4-byte aligned.
48+
///
49+
/// Fixup expression:
50+
/// Fixup <- (Target - Fixup + Addend) >> 2 : int16
51+
///
52+
/// Notes:
53+
/// The '16' in the name refers to the number operand bits and follows the
54+
/// naming convention used by the corresponding ELF relocations. Since the low
55+
/// two bits must be zero (because of the 4-byte alignment of the target) the
56+
/// operand is effectively a signed 18-bit number.
57+
///
58+
/// Errors:
59+
/// - The result of the unshifted part of the fixup expression must be
60+
/// 4-byte aligned otherwise an alignment error will be returned.
61+
/// - The result of the fixup expression must fit into an int16 otherwise an
62+
/// out-of-range error will be returned.
63+
///
64+
Branch16PCRel,
65+
66+
/// A 21-bit PC-relative branch.
67+
///
68+
/// Represents a PC-relative branch to a target within +/-4Mb. The Target must
69+
/// be 4-byte aligned.
70+
///
71+
/// Fixup expression:
72+
/// Fixup <- (Target - Fixup + Addend) >> 2 : int21
73+
///
74+
/// Notes:
75+
/// The '21' in the name refers to the number operand bits and follows the
76+
/// naming convention used by the corresponding ELF relocations. Since the low
77+
/// two bits must be zero (because of the 4-byte alignment of the target) the
78+
/// operand is effectively a signed 23-bit number.
79+
///
80+
/// Errors:
81+
/// - The result of the unshifted part of the fixup expression must be
82+
/// 4-byte aligned otherwise an alignment error will be returned.
83+
/// - The result of the fixup expression must fit into an int21 otherwise an
84+
/// out-of-range error will be returned.
85+
///
86+
Branch21PCRel,
87+
4488
/// A 26-bit PC-relative branch.
4589
///
4690
/// Represents a PC-relative call or branch to a target within +/-128Mb. The
@@ -213,6 +257,37 @@ inline Error applyFixup(LinkGraph &G, Block &B, const Edge &E) {
213257
*(ulittle32_t *)FixupPtr = Value;
214258
break;
215259
}
260+
case Branch16PCRel: {
261+
int64_t Value = TargetAddress - FixupAddress + Addend;
262+
263+
if (!isInt<18>(Value))
264+
return makeTargetOutOfRangeError(G, B, E);
265+
266+
if (!isShiftedInt<16, 2>(Value))
267+
return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
268+
269+
uint32_t RawInstr = *(little32_t *)FixupPtr;
270+
uint32_t Imm = static_cast<uint32_t>(Value >> 2);
271+
uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10;
272+
*(little32_t *)FixupPtr = RawInstr | Imm15_0;
273+
break;
274+
}
275+
case Branch21PCRel: {
276+
int64_t Value = TargetAddress - FixupAddress + Addend;
277+
278+
if (!isInt<23>(Value))
279+
return makeTargetOutOfRangeError(G, B, E);
280+
281+
if (!isShiftedInt<21, 2>(Value))
282+
return makeAlignmentError(orc::ExecutorAddr(FixupAddress), Value, 4, E);
283+
284+
uint32_t RawInstr = *(little32_t *)FixupPtr;
285+
uint32_t Imm = static_cast<uint32_t>(Value >> 2);
286+
uint32_t Imm15_0 = extractBits(Imm, /*Hi=*/15, /*Lo=*/0) << 10;
287+
uint32_t Imm20_16 = extractBits(Imm, /*Hi=*/20, /*Lo=*/16);
288+
*(little32_t *)FixupPtr = RawInstr | Imm15_0 | Imm20_16;
289+
break;
290+
}
216291
case Branch26PCRel: {
217292
int64_t Value = TargetAddress - FixupAddress + Addend;
218293

0 commit comments

Comments
 (0)