Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -631,10 +631,49 @@ RValue CIRGenFunction::emitLoadOfLValue(LValue lv, SourceLocation loc) {
lv.getVectorIdx()));
}

if (lv.isExtVectorElt())
return emitLoadOfExtVectorElementLValue(lv);

cgm.errorNYI(loc, "emitLoadOfLValue");
return RValue::get(nullptr);
}

int64_t CIRGenFunction::getAccessedFieldNo(unsigned int idx,
const mlir::ArrayAttr elts) {
auto elt = mlir::cast<mlir::IntegerAttr>(elts[idx]);
return elt.getInt();
}

// If this is a reference to a subset of the elements of a vector, create an
// appropriate shufflevector.
RValue CIRGenFunction::emitLoadOfExtVectorElementLValue(LValue lv) {
mlir::Location loc = lv.getExtVectorPointer().getLoc();
mlir::Value vec = builder.createLoad(loc, lv.getExtVectorAddress());

// HLSL allows treating scalars as one-element vectors. Converting the scalar
// IR value to a vector here allows the rest of codegen to behave as normal.
if (getLangOpts().HLSL && !mlir::isa<cir::VectorType>(vec.getType())) {
cgm.errorNYI(loc, "emitLoadOfExtVectorElementLValue: HLSL");
return {};
}

const mlir::ArrayAttr elts = lv.getExtVectorElts();

// If the result of the expression is a non-vector type, we must be extracting
// a single element. Just codegen as an extractelement.
const auto *exprVecTy = lv.getType()->getAs<clang::VectorType>();
if (!exprVecTy) {
int64_t indexValue = getAccessedFieldNo(0, elts);
cir::ConstantOp index =
builder.getConstInt(loc, builder.getSInt64Ty(), indexValue);
return RValue::get(cir::VecExtractOp::create(builder, loc, vec, index));
}

cgm.errorNYI(
loc, "emitLoadOfExtVectorElementLValue: Result of expr is vector type");
return {};
}

static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) {
assert(!cir::MissingFeatures::weakRefReference());
return cgm.getAddrOfFunction(gd);
Expand Down Expand Up @@ -1120,6 +1159,46 @@ CIRGenFunction::emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e) {
return lv;
}

LValue CIRGenFunction::emitExtVectorElementExpr(const ExtVectorElementExpr *e) {
// Emit the base vector as an l-value.
LValue base;

// ExtVectorElementExpr's base can either be a vector or pointer to vector.
if (e->isArrow()) {
cgm.errorNYI(e->getSourceRange(),
"emitExtVectorElementExpr: pointer to vector");
return {};
} else if (e->getBase()->isGLValue()) {
// Otherwise, if the base is an lvalue ( as in the case of foo.x.x),
// emit the base as an lvalue.
assert(e->getBase()->getType()->isVectorType());
base = emitLValue(e->getBase());
} else {
// Otherwise, the base is a normal rvalue (as in (V+V).x), emit it as such.
cgm.errorNYI(e->getSourceRange(),
"emitExtVectorElementExpr: base is a normal rvalue");
return {};
}

QualType type =
e->getType().withCVRQualifiers(base.getQuals().getCVRQualifiers());

// Encode the element access list into a vector of unsigned indices.
SmallVector<uint32_t, 4> indices;
e->getEncodedElementAccess(indices);

if (base.isSimple()) {
SmallVector<int64_t> attrElts(indices.begin(), indices.end());
mlir::ArrayAttr elts = builder.getI64ArrayAttr(attrElts);
return LValue::makeExtVectorElt(base.getAddress(), elts, type,
base.getBaseInfo());
}

cgm.errorNYI(e->getSourceRange(),
"emitExtVectorElementExpr: isSimple is false");
return {};
}

LValue CIRGenFunction::emitStringLiteralLValue(const StringLiteral *e,
llvm::StringRef name) {
cir::GlobalOp globalOp = cgm.getGlobalForStringLiteral(e, name);
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,8 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
e->getSourceRange().getBegin());
}

mlir::Value VisitExtVectorElementExpr(Expr *e) { return emitLoadOfLValue(e); }

mlir::Value VisitMemberExpr(MemberExpr *e);

mlir::Value VisitCompoundLiteralExpr(CompoundLiteralExpr *e) {
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,8 @@ LValue CIRGenFunction::emitLValue(const Expr *e) {
return emitConditionalOperatorLValue(cast<BinaryConditionalOperator>(e));
case Expr::ArraySubscriptExprClass:
return emitArraySubscriptExpr(cast<ArraySubscriptExpr>(e));
case Expr::ExtVectorElementExprClass:
return emitExtVectorElementExpr(cast<ExtVectorElementExpr>(e));
case Expr::UnaryOperatorClass:
return emitUnaryOpLValue(cast<UnaryOperator>(e));
case Expr::StringLiteralClass:
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1277,6 +1277,8 @@ class CIRGenFunction : public CIRGenTypeCache {
QualType &baseType, Address &addr);
LValue emitArraySubscriptExpr(const clang::ArraySubscriptExpr *e);

LValue emitExtVectorElementExpr(const ExtVectorElementExpr *e);

Address emitArrayToPointerDecay(const Expr *e,
LValueBaseInfo *baseInfo = nullptr);

Expand Down Expand Up @@ -1342,6 +1344,8 @@ class CIRGenFunction : public CIRGenTypeCache {
mlir::Value emittedE,
bool isDynamic);

int64_t getAccessedFieldNo(unsigned idx, mlir::ArrayAttr elts);

RValue emitCall(const CIRGenFunctionInfo &funcInfo,
const CIRGenCallee &callee, ReturnValueSlot returnValue,
const CallArgList &args, cir::CIRCallOpInterface *callOp,
Expand Down Expand Up @@ -1637,6 +1641,8 @@ class CIRGenFunction : public CIRGenTypeCache {
/// Load a complex number from the specified l-value.
mlir::Value emitLoadOfComplex(LValue src, SourceLocation loc);

RValue emitLoadOfExtVectorElementLValue(LValue lv);

/// Given an expression that represents a value lvalue, this method emits
/// the address of the lvalue, then loads the result as an rvalue,
/// returning the rvalue.
Expand Down
33 changes: 32 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,8 @@ class LValue {
// this is the alignment of the whole vector)
unsigned alignment;
mlir::Value v;
mlir::Value vectorIdx; // Index for vector subscript
mlir::Value vectorIdx; // Index for vector subscript
mlir::Attribute vectorElts; // ExtVector element subset: V.xyx
mlir::Type elementType;
LValueBaseInfo baseInfo;
const CIRGenBitFieldInfo *bitFieldInfo{nullptr};
Expand All @@ -190,6 +191,7 @@ class LValue {
bool isSimple() const { return lvType == Simple; }
bool isVectorElt() const { return lvType == VectorElt; }
bool isBitField() const { return lvType == BitField; }
bool isExtVectorElt() const { return lvType == ExtVectorElt; }
bool isGlobalReg() const { return lvType == GlobalReg; }
bool isVolatile() const { return quals.hasVolatile(); }

Expand Down Expand Up @@ -254,6 +256,22 @@ class LValue {
return vectorIdx;
}

// extended vector elements.
Address getExtVectorAddress() const {
assert(isExtVectorElt());
return Address(getExtVectorPointer(), elementType, getAlignment());
}

mlir::Value getExtVectorPointer() const {
assert(isExtVectorElt());
return v;
}

mlir::ArrayAttr getExtVectorElts() const {
assert(isExtVectorElt());
return mlir::cast<mlir::ArrayAttr>(vectorElts);
}

static LValue makeVectorElt(Address vecAddress, mlir::Value index,
clang::QualType t, LValueBaseInfo baseInfo) {
LValue r;
Expand All @@ -265,6 +283,19 @@ class LValue {
return r;
}

static LValue makeExtVectorElt(Address vecAddress, mlir::ArrayAttr elts,
clang::QualType type,
LValueBaseInfo baseInfo) {
LValue r;
r.lvType = ExtVectorElt;
r.v = vecAddress.getPointer();
r.elementType = vecAddress.getElementType();
r.vectorElts = elts;
r.initialize(type, type.getQualifiers(), vecAddress.getAlignment(),
baseInfo);
return r;
}

// bitfield lvalue
Address getBitFieldAddress() const {
return Address(getBitFieldPointer(), elementType, getAlignment());
Expand Down
46 changes: 46 additions & 0 deletions clang/test/CIR/CodeGen/vector-ext-element.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG

typedef int vi4 __attribute__((ext_vector_type(4)));

void element_expr_from_gl() {
vi4 a;
int x = a.x;
int y = a.y;
}

// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a"]
// CIR: %[[X_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["x", init]
// CIR: %[[Y_ADDR:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>, ["y", init]
// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i>
// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !s64i
// CIR: %[[ELEM_0:.*]] = cir.vec.extract %[[TMP_A]][%[[CONST_0]] : !s64i] : !cir.vector<4 x !s32i>
// CIR: cir.store {{.*}} %[[ELEM_0]], %[[X_ADDR]] : !s32i, !cir.ptr<!s32i>
// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i>
// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s64i
// CIR: %[[ELEM_1:.*]] = cir.vec.extract %[[TMP_A]][%[[CONST_1]] : !s64i] : !cir.vector<4 x !s32i>
// CIR: cir.store {{.*}} %[[ELEM_1]], %[[Y_ADDR]] : !s32i, !cir.ptr<!s32i>

// LLVM: %[[A_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16
// LLVM: %[[X_ADDR:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[Y_ADDR:.*]] = alloca i32, i64 1, align 4
// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16
// LLVM: %[[ELEM_0:.*]] = extractelement <4 x i32> %4, i64 0
// LLVM: store i32 %[[ELEM_0]], ptr %[[X_ADDR]], align 4
// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16
// LLVM: %[[ELEM_1:.*]] = extractelement <4 x i32> %6, i64 1
// LLVM: store i32 %[[ELEM_1]], ptr %[[Y_ADDR]], align 4

// OGCG: %[[A_ADDR:.*]] = alloca <4 x i32>, align 16
// OGCG: %[[X_ADDR:.*]] = alloca i32, align 4
// OGCG: %[[Y_ADDR:.*]] = alloca i32, align 4
// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16
// OGCG: %[[ELEM_0:.*]] = extractelement <4 x i32> %[[TMP_A]], i64 0
// OGCG: store i32 %[[ELEM_0]], ptr %[[X_ADDR]], align 4
// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16
// OGCG: %[[ELEM_1:.*]] = extractelement <4 x i32> %[[TMP_A]], i64 1
// OGCG: store i32 %[[ELEM_1]], ptr %[[Y_ADDR]], align 4
Loading