Skip to content

Commit d040975

Browse files
SC llvm teamSC llvm team
authored andcommitted
Merged main:dc5341069315 into amd-gfx:1ab2a8935a2c
Local branch amd-gfx 1ab2a89 Merged main:ab261eb38a6e into amd-gfx:716677fafc9c Remote branch main dc53410 [libc++] <experimental/simd> Add operator value_type() of simd reference (llvm#68960)
2 parents 1ab2a89 + dc53410 commit d040975

File tree

34 files changed

+408
-126
lines changed

34 files changed

+408
-126
lines changed

bolt/include/bolt/Core/BinaryFunction.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1721,14 +1721,7 @@ class BinaryFunction {
17211721
// Align data in code BFs minimum to CI alignment
17221722
if (!size() && hasIslandsInfo())
17231723
return getConstantIslandAlignment();
1724-
1725-
// Minimal code alignment on AArch64 and RISCV is 4
1726-
if (BC.isAArch64() || BC.isRISCV())
1727-
return 4;
1728-
1729-
// We have to use at least 2-byte alignment for functions because
1730-
// of C++ ABI.
1731-
return 2;
1724+
return BC.MIB->getMinFunctionAlignment();
17321725
}
17331726

17341727
Align getMinAlign() const { return Align(getMinAlignment()); }

bolt/include/bolt/Core/MCPlusBuilder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2077,6 +2077,12 @@ class MCPlusBuilder {
20772077
return BlocksVectorTy();
20782078
}
20792079

2080+
virtual uint16_t getMinFunctionAlignment() const {
2081+
// We have to use at least 2-byte alignment for functions because of C++
2082+
// ABI.
2083+
return 2;
2084+
}
2085+
20802086
// AliasMap caches a mapping of registers to the set of registers that
20812087
// alias (are sub or superregs of itself, including itself).
20822088
std::vector<BitVector> AliasMap;

bolt/lib/Target/AArch64/AArch64MCPlusBuilder.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1643,6 +1643,8 @@ class AArch64MCPlusBuilder : public MCPlusBuilder {
16431643

16441644
return Relocation({RelOffset, RelSymbol, RelType, RelAddend, 0});
16451645
}
1646+
1647+
uint16_t getMinFunctionAlignment() const override { return 4; }
16461648
};
16471649

16481650
} // end anonymous namespace

bolt/lib/Target/RISCV/RISCVMCPlusBuilder.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "bolt/Core/MCPlusBuilder.h"
1616
#include "llvm/BinaryFormat/ELF.h"
1717
#include "llvm/MC/MCInst.h"
18+
#include "llvm/MC/MCSubtargetInfo.h"
1819
#include "llvm/Support/Debug.h"
1920
#include "llvm/Support/ErrorHandling.h"
2021
#include "llvm/Support/Format.h"
@@ -490,6 +491,13 @@ class RISCVMCPlusBuilder : public MCPlusBuilder {
490491
assert(Second.getOpcode() == RISCV::JALR);
491492
return true;
492493
}
494+
495+
uint16_t getMinFunctionAlignment() const override {
496+
if (STI->hasFeature(RISCV::FeatureStdExtC) ||
497+
STI->hasFeature(RISCV::FeatureStdExtZca))
498+
return 2;
499+
return 4;
500+
}
493501
};
494502

495503
} // end anonymous namespace

bolt/test/RISCV/function-alignment.s

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
## Test that BOLT uses a minimum function alignment of 4 (or 2 for RVC) bytes.
2+
3+
# RUN: llvm-mc -triple=riscv64 -filetype=obj -o %t.o %s
4+
# RUN: ld.lld -q -o %t %t.o
5+
# RUN: llvm-bolt --align-functions=1 --use-old-text=0 -o %t.bolt %t
6+
# RUN: llvm-nm -n %t.bolt | FileCheck %s
7+
8+
# RUN: llvm-mc -triple=riscv64 -mattr=+c -filetype=obj -o %t-c.o %s
9+
# RUN: ld.lld -q -o %t-c %t-c.o
10+
# RUN: llvm-bolt --align-functions=1 --use-old-text=0 -o %t-c.bolt %t-c
11+
# RUN: llvm-nm -n %t-c.bolt | FileCheck --check-prefix=CHECK-C %s
12+
13+
# CHECK: {{[048c]}} T _start
14+
# CHECK-NEXT: {{[048c]}} T dummy
15+
16+
# CHECK-C: {{[02468ace]}} T _start
17+
# CHECK-C-NEXT: {{[02468ace]}} T dummy
18+
19+
.text
20+
21+
# Make sure input binary is only 1 byte aligned. BOLT should increase the
22+
# alignment to 2 or 4 bytes.
23+
.byte 0
24+
.balign 1
25+
26+
.globl _start
27+
.type _start, @function
28+
_start:
29+
# Dummy reloc to force relocation mode.
30+
.reloc 0, R_RISCV_NONE
31+
ret
32+
.size _start, .-_start
33+
34+
.globl dummy
35+
.type dummy, @function
36+
dummy:
37+
ret
38+
.size dummy, .-dummy

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,9 @@ Bug Fixes in This Version
442442
- Clang no longer permits using the `_BitInt` types as an underlying type for an
443443
enumeration as specified in the C23 Standard.
444444
Fixes (`#69619 <https://github.com/llvm/llvm-project/issues/69619>`_)
445+
- Clang now accepts anonymous members initialized with designated initializers
446+
inside templates.
447+
Fixes (`#65143 <https://github.com/llvm/llvm-project/issues/65143>`_)
445448

446449
Bug Fixes to Compiler Builtins
447450
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/TreeTransform.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11783,21 +11783,23 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) {
1178311783
bool ExprChanged = false;
1178411784
for (const DesignatedInitExpr::Designator &D : E->designators()) {
1178511785
if (D.isFieldDesignator()) {
11786-
Desig.AddDesignator(Designator::CreateFieldDesignator(
11787-
D.getFieldName(), D.getDotLoc(), D.getFieldLoc()));
1178811786
if (D.getFieldDecl()) {
1178911787
FieldDecl *Field = cast_or_null<FieldDecl>(
1179011788
getDerived().TransformDecl(D.getFieldLoc(), D.getFieldDecl()));
1179111789
if (Field != D.getFieldDecl())
1179211790
// Rebuild the expression when the transformed FieldDecl is
1179311791
// different to the already assigned FieldDecl.
1179411792
ExprChanged = true;
11793+
if (Field->isAnonymousStructOrUnion())
11794+
continue;
1179511795
} else {
1179611796
// Ensure that the designator expression is rebuilt when there isn't
1179711797
// a resolved FieldDecl in the designator as we don't want to assign
1179811798
// a FieldDecl to a pattern designator that will be instantiated again.
1179911799
ExprChanged = true;
1180011800
}
11801+
Desig.AddDesignator(Designator::CreateFieldDesignator(
11802+
D.getFieldName(), D.getDotLoc(), D.getFieldLoc()));
1180111803
continue;
1180211804
}
1180311805

clang/test/SemaCXX/cxx2b-designated-initializers.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,36 @@ union S {
99
};
1010

1111
void f(int x, auto) {
12-
const S result { // expected-error {{field designator (null) does not refer to any field in type 'const S'}}
12+
const S result {
1313
.a = x
1414
};
1515
}
1616

1717
void g(void) {
18-
f(0, 0); // expected-note {{in instantiation of function template specialization 'PR61118::f<int>' requested here}}
18+
f(0, 0);
1919
}
2020

2121
} // end namespace PR61118
2222

23+
namespace GH65143 {
24+
struct Inner {
25+
int a;
26+
};
27+
28+
struct Outer {
29+
struct {
30+
Inner inner;
31+
};
32+
};
33+
34+
template <int val> void f() {
35+
constexpr Outer x{.inner = {val}};
36+
static_assert(x.inner.a == val);
37+
}
38+
39+
void bar() { f<4>(); }
40+
}
41+
2342
namespace GH62156 {
2443
union U1 {
2544
int x;

flang/include/flang/Evaluate/intrinsics.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,9 @@ class IntrinsicProcTable {
9999
// On success, the actual arguments are transferred to the result
100100
// in dummy argument order; on failure, the actual arguments remain
101101
// untouched.
102+
// For MIN and MAX, only a1 and a2 actual arguments are transferred in dummy
103+
// order on success and the other arguments are transferred afterwards
104+
// without being sorted.
102105
std::optional<SpecificCall> Probe(
103106
const CallCharacteristics &, ActualArguments &, FoldingContext &) const;
104107

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 62 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,63 +1446,75 @@ static std::int64_t GetBuiltinKind(
14461446

14471447
// Ensure that the keywords of arguments to MAX/MIN and their variants
14481448
// are of the form A123 with no duplicates or leading zeroes.
1449-
static bool CheckMaxMinArgument(std::optional<parser::CharBlock> keyword,
1449+
static bool CheckMaxMinArgument(parser::CharBlock keyword,
14501450
std::set<parser::CharBlock> &set, const char *intrinsicName,
14511451
parser::ContextualMessages &messages) {
1452-
if (keyword) {
1453-
std::size_t j{1};
1454-
for (; j < keyword->size(); ++j) {
1455-
char ch{(*keyword)[j]};
1456-
if (ch < (j == 1 ? '1' : '0') || ch > '9') {
1457-
break;
1458-
}
1452+
std::size_t j{1};
1453+
for (; j < keyword.size(); ++j) {
1454+
char ch{(keyword)[j]};
1455+
if (ch < (j == 1 ? '1' : '0') || ch > '9') {
1456+
break;
14591457
}
1460-
if (keyword->size() < 2 || (*keyword)[0] != 'a' || j < keyword->size()) {
1461-
messages.Say(*keyword,
1462-
"Argument keyword '%s=' is not known in call to '%s'"_err_en_US,
1463-
*keyword, intrinsicName);
1458+
}
1459+
if (keyword.size() < 2 || (keyword)[0] != 'a' || j < keyword.size()) {
1460+
messages.Say(keyword,
1461+
"argument keyword '%s=' is not known in call to '%s'"_err_en_US,
1462+
keyword, intrinsicName);
1463+
return false;
1464+
}
1465+
if (!set.insert(keyword).second) {
1466+
messages.Say(keyword,
1467+
"argument keyword '%s=' was repeated in call to '%s'"_err_en_US,
1468+
keyword, intrinsicName);
1469+
return false;
1470+
}
1471+
return true;
1472+
}
1473+
1474+
// Validate the keyword, if any, and ensure that A1 and A2 are always placed in
1475+
// first and second position in actualForDummy. A1 and A2 are special since they
1476+
// are not optional. The rest of the arguments are not sorted, there are no
1477+
// differences between them.
1478+
static bool CheckAndPushMinMaxArgument(ActualArgument &arg,
1479+
std::vector<ActualArgument *> &actualForDummy,
1480+
std::set<parser::CharBlock> &set, const char *intrinsicName,
1481+
parser::ContextualMessages &messages) {
1482+
if (std::optional<parser::CharBlock> keyword{arg.keyword()}) {
1483+
if (!CheckMaxMinArgument(*keyword, set, intrinsicName, messages)) {
14641484
return false;
14651485
}
1466-
auto [_, wasInserted]{set.insert(*keyword)};
1467-
if (!wasInserted) {
1486+
const bool isA1{*keyword == parser::CharBlock{"a1", 2}};
1487+
if (isA1 && !actualForDummy[0]) {
1488+
actualForDummy[0] = &arg;
1489+
return true;
1490+
}
1491+
const bool isA2{*keyword == parser::CharBlock{"a2", 2}};
1492+
if (isA2 && !actualForDummy[1]) {
1493+
actualForDummy[1] = &arg;
1494+
return true;
1495+
}
1496+
if (isA1 || isA2) {
1497+
// Note that for arguments other than a1 and a2, this error will be caught
1498+
// later in check-call.cpp.
14681499
messages.Say(*keyword,
1469-
"Argument keyword '%s=' was repeated in call to '%s'"_err_en_US,
1500+
"keyword argument '%s=' to intrinsic '%s' was supplied "
1501+
"positionally by an earlier actual argument"_err_en_US,
14701502
*keyword, intrinsicName);
14711503
return false;
14721504
}
1473-
}
1474-
return true;
1475-
}
1476-
1477-
static void CheckMaxMinA1A2Argument(const ActualArguments &arguments,
1478-
std::set<parser::CharBlock> &set, parser::ContextualMessages &messages) {
1479-
parser::CharBlock kwA1{"a1", 2};
1480-
parser::CharBlock kwA2{"a2", 2};
1481-
bool missingA1{set.find(kwA1) == set.end()};
1482-
bool missingA2{set.find(kwA2) == set.end()};
1483-
1484-
if (arguments.size() > 1) {
1485-
if (arguments.at(0)->keyword()) {
1486-
// If the keyword is specified in the first argument, the following
1487-
// arguments must have the keywords.
1488-
if (missingA1 && missingA2) {
1489-
messages.Say("missing mandatory '%s=' and '%s=' arguments"_err_en_US,
1490-
kwA1.ToString(), kwA2.ToString());
1491-
} else if (missingA1 && !missingA2) {
1492-
messages.Say(
1493-
"missing mandatory '%s=' argument"_err_en_US, kwA1.ToString());
1494-
} else if (!missingA1 && missingA2) {
1495-
messages.Say(
1496-
"missing mandatory '%s=' argument"_err_en_US, kwA2.ToString());
1497-
}
1498-
} else if (arguments.at(1)->keyword()) {
1499-
// No keyword is specified in the first argument.
1500-
if (missingA1 && missingA2) {
1501-
messages.Say(
1502-
"missing mandatory '%s=' argument"_err_en_US, kwA2.ToString());
1505+
} else {
1506+
if (actualForDummy.size() == 2) {
1507+
if (!actualForDummy[0] && !actualForDummy[1]) {
1508+
actualForDummy[0] = &arg;
1509+
return true;
1510+
} else if (!actualForDummy[1]) {
1511+
actualForDummy[1] = &arg;
1512+
return true;
15031513
}
15041514
}
15051515
}
1516+
actualForDummy.push_back(&arg);
1517+
return true;
15061518
}
15071519

15081520
static bool CheckAtomicKind(const ActualArgument &arg,
@@ -1552,7 +1564,7 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
15521564
bool isMaxMin{dummyArgPatterns > 0 &&
15531565
dummy[dummyArgPatterns - 1].optionality == Optionality::repeats};
15541566
std::vector<ActualArgument *> actualForDummy(
1555-
isMaxMin ? 0 : dummyArgPatterns, nullptr);
1567+
isMaxMin ? 2 : dummyArgPatterns, nullptr);
15561568
bool anyMissingActualArgument{false};
15571569
std::set<parser::CharBlock> maxMinKeywords;
15581570
bool anyKeyword{false};
@@ -1579,9 +1591,8 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
15791591
continue;
15801592
}
15811593
if (isMaxMin) {
1582-
if (CheckMaxMinArgument(arg->keyword(), maxMinKeywords, name, messages)) {
1583-
actualForDummy.push_back(&*arg);
1584-
} else {
1594+
if (!CheckAndPushMinMaxArgument(
1595+
*arg, actualForDummy, maxMinKeywords, name, messages)) {
15851596
return std::nullopt;
15861597
}
15871598
} else {
@@ -1627,17 +1638,6 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
16271638
}
16281639
}
16291640

1630-
if (isMaxMin) {
1631-
int nArgs{0};
1632-
// max() / max(x) is invalid
1633-
while ((arguments.size() + nArgs) < 2) {
1634-
actualForDummy.push_back(nullptr);
1635-
nArgs++;
1636-
}
1637-
1638-
CheckMaxMinA1A2Argument(arguments, maxMinKeywords, messages);
1639-
}
1640-
16411641
std::size_t dummies{actualForDummy.size()};
16421642

16431643
// Check types and kinds of the actual arguments against the intrinsic's
@@ -1659,18 +1659,8 @@ std::optional<SpecificCall> IntrinsicInterface::Match(
16591659
if (!arg) {
16601660
if (d.optionality == Optionality::required) {
16611661
std::string kw{d.keyword};
1662-
if (isMaxMin && maxMinKeywords.size() == 1) {
1663-
// max(a1=x) or max(a2=x)
1664-
const auto kwA1{dummy[0].keyword};
1665-
const auto kwA2{dummy[1].keyword};
1666-
if (maxMinKeywords.begin()->ToString() == kwA1) {
1667-
messages.Say("missing mandatory 'a2=' argument"_err_en_US);
1668-
} else if (maxMinKeywords.begin()->ToString() == kwA2) {
1669-
messages.Say("missing mandatory 'a1=' argument"_err_en_US);
1670-
} else {
1671-
messages.Say(
1672-
"missing mandatory 'a1=' and 'a2=' arguments"_err_en_US);
1673-
}
1662+
if (isMaxMin && !actualForDummy[0] && !actualForDummy[1]) {
1663+
messages.Say("missing mandatory 'a1=' and 'a2=' arguments"_err_en_US);
16741664
} else {
16751665
messages.Say(
16761666
"missing mandatory '%s=' argument"_err_en_US, kw.c_str());

flang/test/Lower/Intrinsics/min.f90

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
! RUN: bbc -emit-hlfir -o - %s 2>&1 | FileCheck %s
2+
! Test that min/max A(X>2) optional arguments are handled regardless
3+
! of the order in which they appear. Only A1 and A2 are mandatory.
4+
5+
real function test(a, b, c)
6+
real, optional :: a, b, c
7+
test = min(a1=a, a3=c, a2=c)
8+
end function
9+
! CHECK-LABEL: func.func @_QPtest(
10+
! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref<f32> {fir.bindc_name = "a", fir.optional},
11+
! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<f32> {fir.bindc_name = "b", fir.optional},
12+
! CHECK-SAME: %[[VAL_2:.*]]: !fir.ref<f32> {fir.bindc_name = "c", fir.optional}) -> f32 {
13+
! CHECK: %[[VAL_3:.*]]:2 = hlfir.declare %[[VAL_0]] {{.*}}uniq_name = "_QFtestEa"}
14+
! CHECK: %[[VAL_4:.*]]:2 = hlfir.declare %[[VAL_1]] {{.*}}uniq_name = "_QFtestEb"}
15+
! CHECK: %[[VAL_5:.*]]:2 = hlfir.declare %[[VAL_2]] {{.*}}uniq_name = "_QFtestEc"}
16+
! CHECK: %[[VAL_6:.*]] = fir.alloca f32 {bindc_name = "test", uniq_name = "_QFtestEtest"}
17+
! CHECK: %[[VAL_7:.*]]:2 = hlfir.declare %[[VAL_6]] {uniq_name = "_QFtestEtest"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
18+
! CHECK: %[[VAL_8:.*]] = fir.load %[[VAL_3]]#0 : !fir.ref<f32>
19+
! CHECK: %[[VAL_9:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<f32>
20+
! CHECK: %[[VAL_10:.*]] = fir.is_present %[[VAL_5]]#0 : (!fir.ref<f32>) -> i1
21+
! CHECK: %[[VAL_11:.*]] = arith.cmpf olt, %[[VAL_8]], %[[VAL_9]] : f32
22+
! CHECK: %[[VAL_12:.*]] = arith.select %[[VAL_11]], %[[VAL_8]], %[[VAL_9]] : f32
23+
! CHECK: %[[VAL_13:.*]] = fir.if %[[VAL_10]] -> (f32) {
24+
! CHECK: %[[VAL_14:.*]] = fir.load %[[VAL_5]]#0 : !fir.ref<f32>
25+
! CHECK: %[[VAL_15:.*]] = arith.cmpf olt, %[[VAL_12]], %[[VAL_14]] : f32
26+
! CHECK: %[[VAL_16:.*]] = arith.select %[[VAL_15]], %[[VAL_12]], %[[VAL_14]] : f32
27+
! CHECK: fir.result %[[VAL_16]] : f32
28+
! CHECK: } else {
29+
! CHECK: fir.result %[[VAL_12]] : f32
30+
! CHECK: }
31+
! CHECK: hlfir.assign %[[VAL_13]] to %[[VAL_7]]#0 : f32, !fir.ref<f32>
32+
! CHECK: %[[VAL_17:.*]] = fir.load %[[VAL_7]]#1 : !fir.ref<f32>
33+
! CHECK: return %[[VAL_17]] : f32
34+
! CHECK: }

0 commit comments

Comments
 (0)