Author: Amr Hesham Date: 2025-05-13T20:17:51+02:00 New Revision: 377cb7fb267031e8815c37fa0e5cadd36d227b11
URL: https://github.com/llvm/llvm-project/commit/377cb7fb267031e8815c37fa0e5cadd36d227b11 DIFF: https://github.com/llvm/llvm-project/commit/377cb7fb267031e8815c37fa0e5cadd36d227b11.diff LOG: [CIR] Upstream shift operators for VectorType (#139465) This change adds support for shift ops for VectorType Issue https://github.com/llvm/llvm-project/issues/136487 Added: Modified: clang/include/clang/CIR/Dialect/IR/CIROps.td clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td clang/lib/CIR/Dialect/IR/CIRDialect.cpp clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp clang/test/CIR/CodeGen/vector-ext.cpp clang/test/CIR/CodeGen/vector.cpp Removed: ################################################################################ diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 251e78aba254e..9f5fa266742e8 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1401,18 +1401,20 @@ def ShiftOp : CIR_Op<"shift", [Pure]> { The `cir.shift` operation performs a bitwise shift, either to the left or to the right, based on the first operand. The second operand specifies the value to be shifted, and the third operand determines the number of - positions by which the shift is applied. Both the second and third operands - are required to be integers. + positions by which the shift is applied, They must be either all vector of + integer type, or all integer type. If they are vectors, each vector element of + the shift target is shifted by the corresponding shift amount in + the shift amount vector. ```mlir - %7 = cir.shift(left, %1 : !u64i, %4 : !s32i) -> !u64i + %res = cir.shift(left, %lhs : !u64i, %amount : !s32i) -> !u64i + %new_vec = cir.shift(left, %lhs : !cir.vector<2 x !s32i>, %rhs : + !cir.vector<2 x !s32i>) -> !cir.vector<2 x !s32i> ``` }]; - // TODO(cir): Support vectors. CIR_IntType -> CIR_AnyIntOrVecOfInt. Also - // update the description above. - let results = (outs CIR_IntType:$result); - let arguments = (ins CIR_IntType:$value, CIR_IntType:$amount, + let results = (outs CIR_AnyIntOrVecOfInt:$result); + let arguments = (ins CIR_AnyIntOrVecOfInt:$value, CIR_AnyIntOrVecOfInt:$amount, UnitAttr:$isShiftleft); let assemblyFormat = [{ diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td index 00f67e2a03a25..902d6535ff717 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypeConstraints.td @@ -174,4 +174,23 @@ def CIR_PtrToVoidPtrType "$_builder.getType<" # cppType # ">(" "cir::VoidType::get($_builder.getContext())))">; +//===----------------------------------------------------------------------===// +// Vector Type predicates +//===----------------------------------------------------------------------===// + +// Vector of integral type +def IntegerVector : Type< + And<[ + CPred<"::mlir::isa<::cir::VectorType>($_self)">, + CPred<"::mlir::isa<::cir::IntType>(" + "::mlir::cast<::cir::VectorType>($_self).getElementType())">, + CPred<"::mlir::cast<::cir::IntType>(" + "::mlir::cast<::cir::VectorType>($_self).getElementType())" + ".isFundamental()"> + ]>, "!cir.vector of !cir.int"> { +} + +// Any Integer or Vector of Integer Constraints +def CIR_AnyIntOrVecOfInt: AnyTypeOf<[CIR_AnyIntType, IntegerVector]>; + #endif // CLANG_CIR_DIALECT_IR_CIRTYPECONSTRAINTS_TD diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index abb0928b377c2..779114e09d834 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -1297,9 +1297,8 @@ OpFoldResult cir::SelectOp::fold(FoldAdaptor adaptor) { LogicalResult cir::ShiftOp::verify() { mlir::Operation *op = getOperation(); mlir::Type resType = getResult().getType(); - assert(!cir::MissingFeatures::vectorType()); - bool isOp0Vec = false; - bool isOp1Vec = false; + const bool isOp0Vec = mlir::isa<cir::VectorType>(op->getOperand(0).getType()); + const bool isOp1Vec = mlir::isa<cir::VectorType>(op->getOperand(1).getType()); if (isOp0Vec != isOp1Vec) return emitOpError() << "input types cannot be one vector and one scalar"; if (isOp1Vec && op->getOperand(1).getType() != resType) { diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 9c46bd385cb93..3c85bb4b6b41d 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -1372,41 +1372,42 @@ mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite( mlir::LogicalResult CIRToLLVMShiftOpLowering::matchAndRewrite( cir::ShiftOp op, OpAdaptor adaptor, mlir::ConversionPatternRewriter &rewriter) const { - auto cirAmtTy = mlir::dyn_cast<cir::IntType>(op.getAmount().getType()); - auto cirValTy = mlir::dyn_cast<cir::IntType>(op.getValue().getType()); + assert((op.getValue().getType() == op.getType()) && + "inconsistent operands' types NYI"); - // Operands could also be vector type - assert(!cir::MissingFeatures::vectorType()); - mlir::Type llvmTy = getTypeConverter()->convertType(op.getType()); + const mlir::Type llvmTy = getTypeConverter()->convertType(op.getType()); mlir::Value amt = adaptor.getAmount(); mlir::Value val = adaptor.getValue(); - // TODO(cir): Assert for vector types - assert((cirValTy && cirAmtTy) && - "shift input type must be integer or vector type, otherwise NYI"); - - assert((cirValTy == op.getType()) && "inconsistent operands' types NYI"); - - // Ensure shift amount is the same type as the value. Some undefined - // behavior might occur in the casts below as per [C99 6.5.7.3]. - // Vector type shift amount needs no cast as type consistency is expected to - // be already be enforced at CIRGen. - if (cirAmtTy) - amt = getLLVMIntCast(rewriter, amt, mlir::cast<mlir::IntegerType>(llvmTy), - true, cirAmtTy.getWidth(), cirValTy.getWidth()); + auto cirAmtTy = mlir::dyn_cast<cir::IntType>(op.getAmount().getType()); + bool isUnsigned; + if (cirAmtTy) { + auto cirValTy = mlir::cast<cir::IntType>(op.getValue().getType()); + isUnsigned = cirValTy.isUnsigned(); + + // Ensure shift amount is the same type as the value. Some undefined + // behavior might occur in the casts below as per [C99 6.5.7.3]. + // Vector type shift amount needs no cast as type consistency is expected to + // be already be enforced at CIRGen. + if (cirAmtTy) + amt = getLLVMIntCast(rewriter, amt, llvmTy, true, cirAmtTy.getWidth(), + cirValTy.getWidth()); + } else { + auto cirValVTy = mlir::cast<cir::VectorType>(op.getValue().getType()); + isUnsigned = + mlir::cast<cir::IntType>(cirValVTy.getElementType()).isUnsigned(); + } // Lower to the proper LLVM shift operation. if (op.getIsShiftleft()) { rewriter.replaceOpWithNewOp<mlir::LLVM::ShlOp>(op, llvmTy, val, amt); - } else { - assert(!cir::MissingFeatures::vectorType()); - bool isUnsigned = !cirValTy.isSigned(); - if (isUnsigned) - rewriter.replaceOpWithNewOp<mlir::LLVM::LShrOp>(op, llvmTy, val, amt); - else - rewriter.replaceOpWithNewOp<mlir::LLVM::AShrOp>(op, llvmTy, val, amt); + return mlir::success(); } + if (isUnsigned) + rewriter.replaceOpWithNewOp<mlir::LLVM::LShrOp>(op, llvmTy, val, amt); + else + rewriter.replaceOpWithNewOp<mlir::LLVM::AShrOp>(op, llvmTy, val, amt); return mlir::success(); } diff --git a/clang/test/CIR/CodeGen/vector-ext.cpp b/clang/test/CIR/CodeGen/vector-ext.cpp index 095bff13ddefc..a16ef42f113df 100644 --- a/clang/test/CIR/CodeGen/vector-ext.cpp +++ b/clang/test/CIR/CodeGen/vector-ext.cpp @@ -336,3 +336,68 @@ void foo7() { // OGCG: %[[TMP2:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 // OGCG: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP2]], i32 %[[RES]], i32 2 // OGCG: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 + +void foo9() { + vi4 a = {1, 2, 3, 4}; + vi4 b = {5, 6, 7, 8}; + + vi4 shl = a << b; + vi4 shr = a >> b; +} + +// CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a", init] +// CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["b", init] +// CIR: %[[SHL_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["shl", init] +// CIR: %[[SHR_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["shr", init] +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i +// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i +// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : +// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: cir.store %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[CONST_5:.*]] = cir.const #cir.int<5> : !s32i +// CIR: %[[CONST_6:.*]] = cir.const #cir.int<6> : !s32i +// CIR: %[[CONST_7:.*]] = cir.const #cir.int<7> : !s32i +// CIR: %[[CONST_8:.*]] = cir.const #cir.int<8> : !s32i +// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create(%[[CONST_5]], %[[CONST_6]], %[[CONST_7]], %[[CONST_8]] : +// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: cir.store %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[TMP_A:.*]] = cir.load %[[VEC_A]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[TMP_B:.*]] = cir.load %[[VEC_B]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[SHL:.*]] = cir.shift(left, %[[TMP_A]] : !cir.vector<4 x !s32i>, %[[TMP_B]] : !cir.vector<4 x !s32i>) -> !cir.vector<4 x !s32i> +// CIR: cir.store %[[SHL]], %[[SHL_RES]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[TMP_A:.*]] = cir.load %[[VEC_A]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[TMP_B:.*]] = cir.load %[[VEC_B]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[SHR:.*]] = cir.shift(right, %[[TMP_A]] : !cir.vector<4 x !s32i>, %[[TMP_B]] : !cir.vector<4 x !s32i>) -> !cir.vector<4 x !s32i> +// CIR: cir.store %[[SHR]], %[[SHR_RES]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + +// LLVM: %[[VEC_A:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[VEC_B:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[SHL_RES:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[SHR_RES:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC_A]], align 16 +// LLVM: store <4 x i32> <i32 5, i32 6, i32 7, i32 8>, ptr %[[VEC_B]], align 16 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16 +// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16 +// LLVM: %[[SHL:.*]] = shl <4 x i32> %[[TMP_A]], %[[TMP_B]] +// LLVM: store <4 x i32> %[[SHL]], ptr %[[SHL_RES]], align 16 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16 +// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16 +// LLVM: %[[SHR:.*]] = ashr <4 x i32> %[[TMP_A]], %[[TMP_B]] +// LLVM: store <4 x i32> %[[SHR]], ptr %[[SHR_RES]], align 16 + +// OGCG: %[[VEC_A:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[VEC_B:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[SHL_RES:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[SHR_RES:.*]] = alloca <4 x i32>, align 16 +// OGCG: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC_A]], align 16 +// OGCG: store <4 x i32> <i32 5, i32 6, i32 7, i32 8>, ptr %[[VEC_B]], align 16 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16 +// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16 +// OGCG: %[[SHL:.*]] = shl <4 x i32> %[[TMP_A]], %[[TMP_B]] +// OGCG: store <4 x i32> %[[SHL]], ptr %[[SHL_RES]], align 16 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16 +// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16 +// OGCG: %[[SHR:.*]] = ashr <4 x i32> %[[TMP_A]], %[[TMP_B]] +// OGCG: store <4 x i32> %[[SHR]], ptr %[[SHR_RES]], align 16 \ No newline at end of file diff --git a/clang/test/CIR/CodeGen/vector.cpp b/clang/test/CIR/CodeGen/vector.cpp index aaf53b9e02b9a..4546215865095 100644 --- a/clang/test/CIR/CodeGen/vector.cpp +++ b/clang/test/CIR/CodeGen/vector.cpp @@ -324,3 +324,68 @@ void foo7() { // OGCG: %[[TMP2:.*]] = load <4 x i32>, ptr %[[VEC]], align 16 // OGCG: %[[NEW_VEC:.*]] = insertelement <4 x i32> %[[TMP2]], i32 %[[RES]], i32 2 // OGCG: store <4 x i32> %[[NEW_VEC]], ptr %[[VEC]], align 16 + +void foo9() { + vi4 a = {1, 2, 3, 4}; + vi4 b = {5, 6, 7, 8}; + + vi4 shl = a << b; + vi4 shr = a >> b; +} + +// CIR: %[[VEC_A:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a", init] +// CIR: %[[VEC_B:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["b", init] +// CIR: %[[SHL_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["shl", init] +// CIR: %[[SHR_RES:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["shr", init] +// CIR: %[[CONST_1:.*]] = cir.const #cir.int<1> : !s32i +// CIR: %[[CONST_2:.*]] = cir.const #cir.int<2> : !s32i +// CIR: %[[CONST_3:.*]] = cir.const #cir.int<3> : !s32i +// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !s32i +// CIR: %[[VEC_A_VAL:.*]] = cir.vec.create(%[[CONST_1]], %[[CONST_2]], %[[CONST_3]], %[[CONST_4]] : +// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: cir.store %[[VEC_A_VAL]], %[[VEC_A]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[CONST_5:.*]] = cir.const #cir.int<5> : !s32i +// CIR: %[[CONST_6:.*]] = cir.const #cir.int<6> : !s32i +// CIR: %[[CONST_7:.*]] = cir.const #cir.int<7> : !s32i +// CIR: %[[CONST_8:.*]] = cir.const #cir.int<8> : !s32i +// CIR: %[[VEC_B_VAL:.*]] = cir.vec.create(%[[CONST_5]], %[[CONST_6]], %[[CONST_7]], %[[CONST_8]] : +// CIR-SAME: !s32i, !s32i, !s32i, !s32i) : !cir.vector<4 x !s32i> +// CIR: cir.store %[[VEC_B_VAL]], %[[VEC_B]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[TMP_A:.*]] = cir.load %[[VEC_A]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[TMP_B:.*]] = cir.load %[[VEC_B]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[SHL:.*]] = cir.shift(left, %[[TMP_A]] : !cir.vector<4 x !s32i>, %[[TMP_B]] : !cir.vector<4 x !s32i>) -> !cir.vector<4 x !s32i> +// CIR: cir.store %[[SHL]], %[[SHL_RES]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> +// CIR: %[[TMP_A:.*]] = cir.load %[[VEC_A]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[TMP_B:.*]] = cir.load %[[VEC_B]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i> +// CIR: %[[SHR:.*]] = cir.shift(right, %[[TMP_A]] : !cir.vector<4 x !s32i>, %[[TMP_B]] : !cir.vector<4 x !s32i>) -> !cir.vector<4 x !s32i> +// CIR: cir.store %[[SHR]], %[[SHR_RES]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>> + +// LLVM: %[[VEC_A:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[VEC_B:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[SHL_RES:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: %[[SHR_RES:.*]] = alloca <4 x i32>, i64 1, align 16 +// LLVM: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC_A]], align 16 +// LLVM: store <4 x i32> <i32 5, i32 6, i32 7, i32 8>, ptr %[[VEC_B]], align 16 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16 +// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16 +// LLVM: %[[SHL:.*]] = shl <4 x i32> %[[TMP_A]], %[[TMP_B]] +// LLVM: store <4 x i32> %[[SHL]], ptr %[[SHL_RES]], align 16 +// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16 +// LLVM: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16 +// LLVM: %[[SHR:.*]] = ashr <4 x i32> %[[TMP_A]], %[[TMP_B]] +// LLVM: store <4 x i32> %[[SHR]], ptr %[[SHR_RES]], align 16 + +// OGCG: %[[VEC_A:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[VEC_B:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[SHL_RES:.*]] = alloca <4 x i32>, align 16 +// OGCG: %[[SHR_RES:.*]] = alloca <4 x i32>, align 16 +// OGCG: store <4 x i32> <i32 1, i32 2, i32 3, i32 4>, ptr %[[VEC_A]], align 16 +// OGCG: store <4 x i32> <i32 5, i32 6, i32 7, i32 8>, ptr %[[VEC_B]], align 16 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16 +// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16 +// OGCG: %[[SHL:.*]] = shl <4 x i32> %[[TMP_A]], %[[TMP_B]] +// OGCG: store <4 x i32> %[[SHL]], ptr %[[SHL_RES]], align 16 +// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[VEC_A]], align 16 +// OGCG: %[[TMP_B:.*]] = load <4 x i32>, ptr %[[VEC_B]], align 16 +// OGCG: %[[SHR:.*]] = ashr <4 x i32> %[[TMP_A]], %[[TMP_B]] +// OGCG: store <4 x i32> %[[SHR]], ptr %[[SHR_RES]], align 16 \ No newline at end of file _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits