Skip to content

Commit fd62e12

Browse files
author
z1_cciauto
authored
merge main into amd-staging (llvm#3642)
2 parents 677f94b + 8bb4078 commit fd62e12

File tree

63 files changed

+1320
-769
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+1320
-769
lines changed

clang/include/clang/CIR/Dialect/IR/CIROps.td

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3614,4 +3614,86 @@ def CIR_FAbsOp : CIR_UnaryFPToFPBuiltinOp<"fabs", "FAbsOp"> {
36143614
}];
36153615
}
36163616

3617+
//===----------------------------------------------------------------------===//
3618+
// Variadic Operations
3619+
//===----------------------------------------------------------------------===//
3620+
3621+
def CIR_VAStartOp : CIR_Op<"va_start"> {
3622+
let summary = "Starts a variable argument list";
3623+
let description = [{
3624+
The cir.va_start operation models the C/C++ va_start macro by
3625+
initializing a variable argument list at the given va_list storage
3626+
location.
3627+
3628+
The first operand must be a pointer to the target's `va_list`
3629+
representation. This operation has no results and produces its effect by
3630+
mutating the storage referenced by the pointer operand. The second operand
3631+
must be an integer value that contains the expected number of arguments in
3632+
that list.
3633+
3634+
Each `cir.va_start` must be paired with a corresponding `cir.va_end`
3635+
on the same logical `va_list` object along all control-flow paths. After
3636+
`cir.va_end`, the `va_list` must not be accessed unless reinitialized
3637+
with another `cir.va_start`.
3638+
3639+
Lowering maps this to the LLVM intrinsic `llvm.va_start`, passing the
3640+
appropriately decayed pointer to the underlying `va_list` storage.
3641+
3642+
Example:
3643+
3644+
```mlir
3645+
// %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
3646+
%p = cir.cast(array_to_ptrdecay, %args
3647+
: !cir.ptr<!cir.array<!rec___va_list_tag x 1>>),
3648+
!cir.ptr<!rec___va_list_tag>
3649+
%count = cir.load %0 : !cir.ptr<!s32i>, !s32i
3650+
cir.va_start %p %count : !cir.ptr<!rec___va_list_tag>, !s32i
3651+
```
3652+
}];
3653+
let arguments = (ins
3654+
CIR_PointerType:$arg_list,
3655+
CIR_AnyFundamentalIntType:$count
3656+
);
3657+
3658+
let assemblyFormat = [{
3659+
$arg_list $count attr-dict `:` type(operands)
3660+
}];
3661+
}
3662+
3663+
def CIR_VAEndOp : CIR_Op<"va_end"> {
3664+
let summary = "Ends a variable argument list";
3665+
let description = [{
3666+
The `cir.va_end` operation models the C/C++ va_end macro by finalizing
3667+
and cleaning up a variable argument list previously initialized with
3668+
`cir.va_start`.
3669+
3670+
The operand must be a pointer to the target's `va_list` representation.
3671+
This operation has no results and produces its effect by mutating the
3672+
storage referenced by the pointer operand.
3673+
3674+
`cir.va_end` must only be called after a matching `cir.va_start` on the
3675+
same `va_list` along all control-flow paths. After `cir.va_end`, the
3676+
`va_list` is invalid and must not be accessed unless reinitialized.
3677+
3678+
Lowering typically maps this to the LLVM intrinsic `llvm.va_end`,
3679+
passing the appropriately decayed pointer to the underlying `va_list`
3680+
storage.
3681+
3682+
Example:
3683+
```mlir
3684+
// %args : !cir.ptr<!cir.array<!rec___va_list_tag x 1>>
3685+
%p = cir.cast(array_to_ptrdecay, %args
3686+
: !cir.ptr<!cir.array<!rec___va_list_tag x 1>>),
3687+
!cir.ptr<!rec___va_list_tag>
3688+
cir.va_end %p : !cir.ptr<!rec___va_list_tag>
3689+
```
3690+
}];
3691+
3692+
let arguments = (ins CIR_PointerType:$arg_list);
3693+
3694+
let assemblyFormat = [{
3695+
$arg_list attr-dict `:` type(operands)
3696+
}];
3697+
}
3698+
36173699
#endif // CLANG_CIR_DIALECT_IR_CIROPS_TD

clang/lib/AST/ByteCode/Disasm.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ LLVM_DUMP_METHOD void Block::dump(llvm::raw_ostream &OS) const {
545545
OS << " Initialized: " << IsInitialized << "\n";
546546
OS << " Weak: " << isWeak() << "\n";
547547
OS << " Dummy: " << isDummy() << '\n';
548-
OS << " Dynamic: " << IsDynamic << "\n";
548+
OS << " Dynamic: " << isDynamic() << "\n";
549549
}
550550

551551
LLVM_DUMP_METHOD void EvaluationResult::dump() const {

clang/lib/AST/ByteCode/DynamicAllocator.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -101,13 +101,17 @@ Block *DynamicAllocator::allocate(const Descriptor *D, unsigned EvalID,
101101
ID->LifeState =
102102
AllocForm == Form::Operator ? Lifetime::Ended : Lifetime::Started;
103103

104-
B->IsDynamic = true;
105-
106-
if (auto It = AllocationSites.find(D->asExpr()); It != AllocationSites.end())
104+
if (auto It = AllocationSites.find(D->asExpr());
105+
It != AllocationSites.end()) {
107106
It->second.Allocations.emplace_back(std::move(Memory));
108-
else
107+
B->setDynAllocId(It->second.NumAllocs);
108+
++It->second.NumAllocs;
109+
} else {
109110
AllocationSites.insert(
110111
{D->asExpr(), AllocationSite(std::move(Memory), AllocForm)});
112+
B->setDynAllocId(0);
113+
}
114+
assert(B->isDynamic());
111115
return B;
112116
}
113117

clang/lib/AST/ByteCode/DynamicAllocator.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,13 @@ class DynamicAllocator final {
4848

4949
struct AllocationSite {
5050
llvm::SmallVector<Allocation> Allocations;
51+
unsigned NumAllocs = 0;
5152
Form AllocForm;
5253

5354
AllocationSite(std::unique_ptr<std::byte[]> Memory, Form AllocForm)
5455
: AllocForm(AllocForm) {
5556
Allocations.push_back({std::move(Memory)});
57+
++NumAllocs;
5658
}
5759

5860
size_t size() const { return Allocations.size(); }

clang/lib/AST/ByteCode/InterpBlock.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ void Block::removePointer(Pointer *P) {
5656
}
5757

5858
void Block::cleanup() {
59-
if (Pointers == nullptr && !IsDynamic && isDead())
59+
if (Pointers == nullptr && !isDynamic() && isDead())
6060
(reinterpret_cast<DeadBlock *>(this + 1) - 1)->free();
6161
}
6262

@@ -111,7 +111,7 @@ DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
111111
Prev = nullptr;
112112
Root = this;
113113

114-
B.IsDynamic = Blk->IsDynamic;
114+
B.DynAllocId = Blk->DynAllocId;
115115

116116
// Transfer pointers.
117117
B.Pointers = Blk->Pointers;

clang/lib/AST/ByteCode/InterpBlock.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class Block final {
6262

6363
Block(unsigned EvalID, const Descriptor *Desc, bool IsStatic = false,
6464
bool IsExtern = false, bool IsWeak = false, bool IsDummy = false)
65-
: Desc(Desc), EvalID(EvalID), IsStatic(IsStatic), IsDynamic(false) {
65+
: Desc(Desc), EvalID(EvalID), IsStatic(IsStatic) {
6666
assert(Desc);
6767
AccessFlags |= (ExternFlag * IsExtern);
6868
AccessFlags |= (WeakFlag * IsWeak);
@@ -80,7 +80,7 @@ class Block final {
8080
/// Checks if the block is temporary.
8181
bool isTemporary() const { return Desc->IsTemporary; }
8282
bool isWeak() const { return AccessFlags & WeakFlag; }
83-
bool isDynamic() const { return IsDynamic; }
83+
bool isDynamic() const { return (DynAllocId != std::nullopt); }
8484
bool isDummy() const { return AccessFlags & DummyFlag; }
8585
bool isDead() const { return AccessFlags & DeadFlag; }
8686
/// Returns the size of the block.
@@ -160,6 +160,9 @@ class Block final {
160160
AccessFlags |= (DummyFlag * IsDummy);
161161
}
162162

163+
/// To be called by DynamicAllocator.
164+
void setDynAllocId(unsigned ID) { DynAllocId = ID; }
165+
163166
/// Deletes a dead block at the end of its lifetime.
164167
void cleanup();
165168

@@ -183,9 +186,8 @@ class Block final {
183186
/// Flag indicating if the block contents have been initialized
184187
/// via invokeCtor.
185188
bool IsInitialized = false;
186-
/// Flag indicating if this block has been allocated via dynamic
187-
/// memory allocation (e.g. malloc).
188-
bool IsDynamic = false;
189+
/// Allocation ID for this dynamic allocation, if it is one.
190+
UnsignedOrNone DynAllocId = std::nullopt;
189191
/// AccessFlags containing IsExtern, IsDead, IsWeak, and IsDummy bits.
190192
uint8_t AccessFlags = 0;
191193
};

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2474,15 +2474,30 @@ static bool interp__builtin_elementwise_sat(InterpState &S, CodePtr OpPC,
24742474
});
24752475

24762476
APSInt Result;
2477-
if (BuiltinID == Builtin::BI__builtin_elementwise_add_sat) {
2477+
switch (BuiltinID) {
2478+
case Builtin::BI__builtin_elementwise_add_sat:
24782479
Result = APSInt(Elem1.isSigned() ? Elem1.sadd_sat(Elem2)
24792480
: Elem1.uadd_sat(Elem2),
24802481
Call->getType()->isUnsignedIntegerOrEnumerationType());
2481-
} else if (BuiltinID == Builtin::BI__builtin_elementwise_sub_sat) {
2482+
break;
2483+
case Builtin::BI__builtin_elementwise_sub_sat:
24822484
Result = APSInt(Elem1.isSigned() ? Elem1.ssub_sat(Elem2)
24832485
: Elem1.usub_sat(Elem2),
24842486
Call->getType()->isUnsignedIntegerOrEnumerationType());
2485-
} else {
2487+
break;
2488+
case clang::X86::BI__builtin_ia32_pmulhuw128:
2489+
case clang::X86::BI__builtin_ia32_pmulhuw256:
2490+
case clang::X86::BI__builtin_ia32_pmulhuw512:
2491+
Result = APSInt(llvm::APIntOps::mulhu(Elem1, Elem2),
2492+
/*isUnsigned=*/true);
2493+
break;
2494+
case clang::X86::BI__builtin_ia32_pmulhw128:
2495+
case clang::X86::BI__builtin_ia32_pmulhw256:
2496+
case clang::X86::BI__builtin_ia32_pmulhw512:
2497+
Result = APSInt(llvm::APIntOps::mulhs(Elem1, Elem2),
2498+
/*isUnsigned=*/false);
2499+
break;
2500+
default:
24862501
llvm_unreachable("Wrong builtin ID");
24872502
}
24882503

@@ -2976,6 +2991,12 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
29762991

29772992
case Builtin::BI__builtin_elementwise_add_sat:
29782993
case Builtin::BI__builtin_elementwise_sub_sat:
2994+
case clang::X86::BI__builtin_ia32_pmulhuw128:
2995+
case clang::X86::BI__builtin_ia32_pmulhuw256:
2996+
case clang::X86::BI__builtin_ia32_pmulhuw512:
2997+
case clang::X86::BI__builtin_ia32_pmulhw128:
2998+
case clang::X86::BI__builtin_ia32_pmulhw256:
2999+
case clang::X86::BI__builtin_ia32_pmulhw512:
29793000
return interp__builtin_elementwise_sat(S, OpPC, Call, BuiltinID);
29803001

29813002
case Builtin::BI__builtin_elementwise_max:

clang/lib/AST/ByteCode/Pointer.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,7 @@ APValue Pointer::toAPValue(const ASTContext &ASTCtx) const {
179179
else if (const auto *E = Desc->asExpr()) {
180180
if (block()->isDynamic()) {
181181
QualType AllocatedType = getDeclPtr().getFieldDesc()->getDataType(ASTCtx);
182-
// FIXME: Suboptimal counting of dynamic allocations. Move this to Context
183-
// or InterpState?
184-
static int ReportedDynamicAllocs = 0;
185-
DynamicAllocLValue DA(ReportedDynamicAllocs++);
182+
DynamicAllocLValue DA(*block()->DynAllocId);
186183
Base = APValue::LValueBase::getDynamicAlloc(DA, AllocatedType);
187184
} else {
188185
Base = E;

clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,21 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
125125
default:
126126
break;
127127

128+
// C stdarg builtins.
129+
case Builtin::BI__builtin_stdarg_start:
130+
case Builtin::BI__builtin_va_start:
131+
case Builtin::BI__va_start: {
132+
emitVAStart(builtinID == Builtin::BI__va_start
133+
? emitScalarExpr(e->getArg(0))
134+
: emitVAListRef(e->getArg(0)).getPointer(),
135+
emitScalarExpr(e->getArg(1)));
136+
return {};
137+
}
138+
139+
case Builtin::BI__builtin_va_end:
140+
emitVAEnd(emitVAListRef(e->getArg(0)).getPointer());
141+
return {};
142+
128143
case Builtin::BIfabs:
129144
case Builtin::BIfabsf:
130145
case Builtin::BIfabsl:
@@ -375,3 +390,13 @@ mlir::Value CIRGenFunction::emitCheckedArgForAssume(const Expr *e) {
375390
"emitCheckedArgForAssume: sanitizers are NYI");
376391
return {};
377392
}
393+
394+
void CIRGenFunction::emitVAStart(mlir::Value vaList, mlir::Value count) {
395+
// LLVM codegen casts to *i8, no real gain on doing this for CIRGen this
396+
// early, defer to LLVM lowering.
397+
cir::VAStartOp::create(builder, vaList.getLoc(), vaList, count);
398+
}
399+
400+
void CIRGenFunction::emitVAEnd(mlir::Value vaList) {
401+
cir::VAEndOp::create(builder, vaList.getLoc(), vaList);
402+
}

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,8 @@ Address CIRGenFunction::emitPointerWithAlignment(const Expr *expr,
9090
} break;
9191

9292
// Array-to-pointer decay. TODO(cir): BaseInfo and TBAAInfo.
93-
case CK_ArrayToPointerDecay: {
94-
cgm.errorNYI(expr->getSourceRange(),
95-
"emitPointerWithAlignment: array-to-pointer decay");
96-
return Address::invalid();
97-
}
93+
case CK_ArrayToPointerDecay:
94+
return emitArrayToPointerDecay(ce->getSubExpr(), baseInfo);
9895

9996
case CK_UncheckedDerivedToBase:
10097
case CK_DerivedToBase: {
@@ -1626,7 +1623,9 @@ void CIRGenFunction::emitIgnoredExpr(const Expr *e) {
16261623
emitLValue(e);
16271624
}
16281625

1629-
Address CIRGenFunction::emitArrayToPointerDecay(const Expr *e) {
1626+
Address CIRGenFunction::emitArrayToPointerDecay(const Expr *e,
1627+
LValueBaseInfo *baseInfo) {
1628+
assert(!cir::MissingFeatures::opTBAA());
16301629
assert(e->getType()->isArrayType() &&
16311630
"Array to pointer decay must have array source type!");
16321631

0 commit comments

Comments
 (0)