Skip to content

Commit fdd3686

Browse files
dkolsen-pgibcardosolopes
authored andcommitted
[CIR] Vector types, part 2 (#387)
This is part 2 of implementing vector types and vector operations in ClangIR, issue #284. Create new operation `cir.vec.insert`, which changes one element of an existing vector object and returns the modified vector object. The input and output vectors are prvalues; this operation does not touch memory. The assembly format and the order of the arguments match that of llvm.insertelement in the LLVM dialect, since the operations have identical semantics. Implement vector element lvalues in class `LValue`, adding member functions `getVectorAddress()`, `getVectorPointer()`, `getVectorIdx()`, and `MakeVectorElt(...)`. The assembly format for operation `cir.vec.extract` was changed to match that of llvm.extractelement in the LLVM dialect, since the operations have identical semantics. These two features, `cir.vec.insert` and vector element lvalues, are used to implement `v[n] = e`, where `v` is a vector. This is a little tricky, because `v[n]` isn't really an lvalue, as its address cannot be taken. The only place it can be used as an lvalue is on the left-hand side of an assignment. Implement unary operators on vector objects (except for logical not on a vector mask, which will be covered in a future commit for boolean vectors). The code for lowering cir.unary for all types, in `CIRUnaryOpLowering::matchAndRewrite`, was largely rewritten. Support for unary `+` on non-vector pointer types was added. (It was already supported and tested in AST->ClangIR CodeGen, but was missing from ClangIR->LLVM Dialect lowering.) Add tests for all binary vector arithmetic operations other than relational operators and shift operators. There were all working after the previous vector types commit, but only addition had beet tested at the time. Co-authored-by: Bruno Cardoso Lopes <[email protected]>
1 parent ba27183 commit fdd3686

File tree

9 files changed

+519
-93
lines changed

9 files changed

+519
-93
lines changed

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

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1672,14 +1672,39 @@ def GetMemberOp : CIR_Op<"get_member"> {
16721672
let hasVerifier = 1;
16731673
}
16741674

1675+
//===----------------------------------------------------------------------===//
1676+
// VecInsertOp
1677+
//===----------------------------------------------------------------------===//
1678+
1679+
def VecInsertOp : CIR_Op<"vec.insert", [Pure,
1680+
TypesMatchWith<"argument type matches vector element type", "vec", "value",
1681+
"$_self.cast<VectorType>().getEltType()">,
1682+
AllTypesMatch<["result", "vec"]>]> {
1683+
1684+
let summary = "Insert one element into a vector object";
1685+
let description = [{
1686+
The `cir.vec.insert` operation replaces the element of the given vector at
1687+
the given index with the given value. The new vector with the inserted
1688+
element is returned.
1689+
}];
1690+
1691+
let arguments = (ins CIR_VectorType:$vec, AnyType:$value, CIR_IntType:$index);
1692+
let results = (outs CIR_VectorType:$result);
1693+
1694+
let assemblyFormat = [{
1695+
$value `,` $vec `[` $index `:` type($index) `]` attr-dict `:` type($vec)
1696+
}];
1697+
1698+
let hasVerifier = 0;
1699+
}
1700+
16751701
//===----------------------------------------------------------------------===//
16761702
// VecExtractOp
16771703
//===----------------------------------------------------------------------===//
16781704

16791705
def VecExtractOp : CIR_Op<"vec.extract", [Pure,
1680-
TypesMatchWith<"type of 'result' matches element type of 'vec'",
1681-
"vec", "result",
1682-
"$_self.cast<VectorType>().getEltType()">]> {
1706+
TypesMatchWith<"type of 'result' matches element type of 'vec'", "vec",
1707+
"result", "$_self.cast<VectorType>().getEltType()">]> {
16831708

16841709
let summary = "Extract one element from a vector object";
16851710
let description = [{
@@ -1691,7 +1716,7 @@ def VecExtractOp : CIR_Op<"vec.extract", [Pure,
16911716
let results = (outs CIR_AnyType:$result);
16921717

16931718
let assemblyFormat = [{
1694-
$vec `[` $index `:` type($index) `]` type($vec) `->` type($result) attr-dict
1719+
$vec `[` $index `:` type($index) `]` attr-dict `:` type($vec)
16951720
}];
16961721

16971722
let hasVerifier = 0;

clang/lib/CIR/CodeGen/CIRGenExpr.cpp

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -545,16 +545,18 @@ void CIRGenFunction::buildStoreOfScalar(mlir::Value Value, Address Addr,
545545
bool Volatile, QualType Ty,
546546
LValueBaseInfo BaseInfo, bool isInit,
547547
bool isNontemporal) {
548-
if (!CGM.getCodeGenOpts().PreserveVec3Type && Ty->isVectorType() &&
549-
Ty->castAs<clang::VectorType>()->getNumElements() == 3)
550-
llvm_unreachable("NYI: Special treatment of 3-element vectors");
551-
552548
Value = buildToMemory(Value, Ty);
553549

554550
if (Ty->isAtomicType()) {
555551
llvm_unreachable("NYI");
556552
}
557553

554+
if (const auto *ClangVecTy = Ty->getAs<clang::VectorType>()) {
555+
if (!CGM.getCodeGenOpts().PreserveVec3Type &&
556+
ClangVecTy->getNumElements() == 3)
557+
llvm_unreachable("NYI: Special treatment of 3-element vector store");
558+
}
559+
558560
// Update the alloca with more info on initialization.
559561
assert(Addr.getPointer() && "expected pointer to exist");
560562
auto SrcAlloca =
@@ -622,6 +624,18 @@ RValue CIRGenFunction::buildLoadOfBitfieldLValue(LValue LV,
622624
}
623625

624626
void CIRGenFunction::buildStoreThroughLValue(RValue Src, LValue Dst) {
627+
if (!Dst.isSimple()) {
628+
if (Dst.isVectorElt()) {
629+
// Read/modify/write the vector, inserting the new element
630+
mlir::Location loc = Dst.getVectorPointer().getLoc();
631+
mlir::Value Vector = builder.createLoad(loc, Dst.getVectorAddress());
632+
Vector = builder.create<mlir::cir::VecInsertOp>(
633+
loc, Vector, Src.getScalarVal(), Dst.getVectorIdx());
634+
builder.createStore(loc, Vector, Dst.getVectorAddress());
635+
return;
636+
}
637+
llvm_unreachable("NYI: non-simple store through lvalue");
638+
}
625639
assert(Dst.isSimple() && "only implemented simple");
626640

627641
// There's special magic for assigning into an ARC-qualified l-value.
@@ -1387,7 +1401,10 @@ LValue CIRGenFunction::buildArraySubscriptExpr(const ArraySubscriptExpr *E,
13871401
// with this subscript.
13881402
if (E->getBase()->getType()->isVectorType() &&
13891403
!isa<ExtVectorElementExpr>(E->getBase())) {
1390-
llvm_unreachable("vector subscript is NYI");
1404+
LValue LHS = buildLValue(E->getBase());
1405+
auto Index = EmitIdxAfterBase(/*Promote=*/false);
1406+
return LValue::MakeVectorElt(LHS.getAddress(), Index,
1407+
E->getBase()->getType(), LHS.getBaseInfo());
13911408
}
13921409

13931410
// All the other cases basically behave like simple offsetting.
@@ -2370,16 +2387,18 @@ mlir::Value CIRGenFunction::buildLoadOfScalar(Address Addr, bool Volatile,
23702387
QualType Ty, mlir::Location Loc,
23712388
LValueBaseInfo BaseInfo,
23722389
bool isNontemporal) {
2373-
if (!CGM.getCodeGenOpts().PreserveVec3Type && Ty->isVectorType() &&
2374-
Ty->castAs<clang::VectorType>()->getNumElements() == 3)
2375-
llvm_unreachable("NYI: Special treatment of 3-element vectors");
2376-
23772390
// Atomic operations have to be done on integral types
23782391
LValue AtomicLValue = LValue::makeAddr(Addr, Ty, getContext(), BaseInfo);
23792392
if (Ty->isAtomicType() || LValueIsSuitableForInlineAtomic(AtomicLValue)) {
23802393
llvm_unreachable("NYI");
23812394
}
23822395

2396+
if (const auto *ClangVecTy = Ty->getAs<clang::VectorType>()) {
2397+
if (!CGM.getCodeGenOpts().PreserveVec3Type &&
2398+
ClangVecTy->getNumElements() == 3)
2399+
llvm_unreachable("NYI: Special treatment of 3-element vector load");
2400+
}
2401+
23832402
mlir::cir::LoadOp Load = builder.create<mlir::cir::LoadOp>(
23842403
Loc, Addr.getElementType(), Addr.getPointer());
23852404

clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1646,7 +1646,7 @@ mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *E) {
16461646
if (dstTy.isa<mlir::cir::BoolType>())
16471647
return boolVal;
16481648

1649-
llvm_unreachable("destination type for negation unary operator is NYI");
1649+
llvm_unreachable("destination type for logical-not unary operator is NYI");
16501650
}
16511651

16521652
// Conversion from bool, integral, or floating-point to integral or

clang/lib/CIR/CodeGen/CIRGenValue.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ class LValue {
207207
unsigned Alignment;
208208
mlir::Value V;
209209
mlir::Type ElementType;
210+
mlir::Value VectorIdx; // Index for vector subscript
210211
LValueBaseInfo BaseInfo;
211212
const CIRGenBitFieldInfo *BitFieldInfo{0};
212213

@@ -301,6 +302,31 @@ class LValue {
301302
const clang::Qualifiers &getQuals() const { return Quals; }
302303
clang::Qualifiers &getQuals() { return Quals; }
303304

305+
// vector element lvalue
306+
Address getVectorAddress() const {
307+
return Address(getVectorPointer(), ElementType, getAlignment());
308+
}
309+
mlir::Value getVectorPointer() const {
310+
assert(isVectorElt());
311+
return V;
312+
}
313+
mlir::Value getVectorIdx() const {
314+
assert(isVectorElt());
315+
return VectorIdx;
316+
}
317+
318+
static LValue MakeVectorElt(Address vecAddress, mlir::Value Index,
319+
clang::QualType type, LValueBaseInfo BaseInfo) {
320+
LValue R;
321+
R.LVType = VectorElt;
322+
R.V = vecAddress.getPointer();
323+
R.ElementType = vecAddress.getElementType();
324+
R.VectorIdx = Index;
325+
R.Initialize(type, type.getQualifiers(), vecAddress.getAlignment(),
326+
BaseInfo);
327+
return R;
328+
}
329+
304330
// bitfield lvalue
305331
Address getBitFieldAddress() const {
306332
return Address(getBitFieldPointer(), ElementType, getAlignment());

0 commit comments

Comments
 (0)