diff --git a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h index 771b7dd33cd4..48d1f1faf53f 100644 --- a/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h +++ b/clang/include/clang/CIR/Dialect/Builder/CIRBaseBuilder.h @@ -170,7 +170,7 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { /*alignment=*/intAttr, /*mem_order=*/ cir::MemOrderAttr{}, - /*tbaa=*/mlir::ArrayAttr{}); + /*tbaa=*/cir::TBAAAttr{}); } mlir::Value createAlignedLoad(mlir::Location loc, mlir::Value ptr, @@ -357,7 +357,7 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { val.getType()) dst = createPtrBitcast(dst, val.getType()); return create(loc, val, dst, _volatile, align, order, - /*tbaa=*/mlir::ArrayAttr{}); + /*tbaa=*/cir::TBAAAttr{}); } mlir::Value createAlloca(mlir::Location loc, cir::PointerType addrType, @@ -405,7 +405,7 @@ class CIRBaseBuilderTy : public mlir::OpBuilder { cir::CopyOp createCopy(mlir::Value dst, mlir::Value src, bool isVolatile = false) { return create(dst.getLoc(), dst, src, isVolatile, - /*tbaa=*/mlir::ArrayAttr{}); + /*tbaa=*/cir::TBAAAttr{}); } cir::MemCpyOp createMemCpy(mlir::Location loc, mlir::Value dst, diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index e54b52b96c91..e968d4c27fd5 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -24,8 +24,9 @@ include "clang/CIR/Interfaces/ASTAttrInterfaces.td" // CIR Attrs //===----------------------------------------------------------------------===// -class CIR_Attr traits = []> - : AttrDef { +class CIR_Attr traits = [], + string baseCppClass = "::mlir::Attribute"> + : AttrDef { let mnemonic = attrMnemonic; } @@ -1294,8 +1295,7 @@ def GlobalAnnotationValuesAttr : CIR_Attr<"GlobalAnnotationValues", let genVerifyDecl = 1; } -def CIR_TBAAAttr : CIR_Attr<"TBAA", "tbaa", []> { -} +include "clang/CIR/Dialect/IR/CIRTBAAAttrs.td" include "clang/CIR/Dialect/IR/CIROpenCLAttrs.td" diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index e02194ad15e0..36793ba97d52 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -588,7 +588,7 @@ def LoadOp : CIR_Op<"load", [ UnitAttr:$is_volatile, OptionalAttr:$alignment, OptionalAttr:$mem_order, - OptionalAttr:$tbaa + OptionalAttr:$tbaa ); let results = (outs CIR_AnyType:$result); @@ -657,7 +657,7 @@ def StoreOp : CIR_Op<"store", [ UnitAttr:$is_volatile, OptionalAttr:$alignment, OptionalAttr:$mem_order, - OptionalAttr:$tbaa); + OptionalAttr:$tbaa); let assemblyFormat = [{ (`volatile` $is_volatile^)? @@ -4068,7 +4068,7 @@ def CopyOp : CIR_Op<"copy", let arguments = (ins Arg:$dst, Arg:$src, UnitAttr:$is_volatile, - OptionalAttr:$tbaa); + OptionalAttr:$tbaa); let summary = "Copies contents from a CIR pointer to another"; let description = [{ Given two CIR pointers, `src` and `dst`, `cir.copy` will copy the memory diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTBAAAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRTBAAAttrs.td new file mode 100644 index 000000000000..d46880e8541e --- /dev/null +++ b/clang/include/clang/CIR/Dialect/IR/CIRTBAAAttrs.td @@ -0,0 +1,38 @@ +//===----------------------------------------------------------------------===// +// TBAAAttr +//===----------------------------------------------------------------------===// + +def CIR_TBAAAttr : CIR_Attr<"TBAA", "tbaa", []> { + let summary = "CIR dialect TBAA base attribute"; +} + +//===----------------------------------------------------------------------===// +// TBAAScalarAttr +//===----------------------------------------------------------------------===// + +def CIR_TBAAScalarAttr : CIR_Attr<"TBAAScalar", "tbaa_scalar", [], "TBAAAttr"> { + let summary = "Describes a scalar type in TBAA with an identifier."; + + let parameters = (ins CIR_AnyScalarType : $type); + + let description = [{ + Define a TBAA attribute. + + Example: + ```mlir + // CIR_TBAAScalarAttr + #tbaa_scalar = #cir.tbaa_scalar + #tbaa_scalar1 = #cir.tbaa_scalar + ``` + + See the following link for more details: + https://llvm.org/docs/LangRef.html#tbaa-metadata + }]; + + let assemblyFormat = "`<` struct(params) `>`"; +} + +def CIR_AnyTBAAAttr : AnyAttrOf<[ + CIR_TBAAAttr, + CIR_TBAAScalarAttr +]>; diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index d3f49716301d..37810b6886df 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -20,13 +20,18 @@ include "mlir/Interfaces/DataLayoutInterfaces.td" include "mlir/IR/AttrTypeBase.td" include "mlir/IR/EnumAttr.td" +// Specify the TBAA name of CIR_type +class TBAALoweringInfo { + string tbaaName = ""; +} + //===----------------------------------------------------------------------===// // CIR Types //===----------------------------------------------------------------------===// class CIR_Type traits = [], string baseCppClass = "::mlir::Type"> - : TypeDef { + : TypeDef, TBAALoweringInfo { let mnemonic = typeMnemonic; } @@ -74,6 +79,28 @@ def CIR_IntType : CIR_Type<"Int", "int", static bool isValidPrimitiveIntBitwidth(unsigned width) { return width == 8 || width == 16 || width == 32 || width == 64; } + + llvm::StringRef getTBAATypeName() const { + switch (getWidth()) { + case 1: + case 8: { + return "omnipotent char"; + } + case 16: { + return "short"; + } + case 32: { + return "int"; + } + case 64: { + return "long"; + } + default: { + llvm::errs() << "unknown type: " << *this << "\n"; + return "unknown"; + } + } + } }]; let genVerifyDecl = 1; } @@ -140,6 +167,7 @@ class CIR_FloatType ]> {} def CIR_Single : CIR_FloatType<"Single", "float"> { + let tbaaName = "float"; let summary = "CIR single-precision float type"; let description = [{ Floating-point type that represents the `float` type in C/C++. Its @@ -148,6 +176,7 @@ def CIR_Single : CIR_FloatType<"Single", "float"> { } def CIR_Double : CIR_FloatType<"Double", "double"> { + let tbaaName = "double"; let summary = "CIR double-precision float type"; let description = [{ Floating-point type that represents the `double` type in C/C++. Its @@ -184,6 +213,7 @@ def CIR_FP128 : CIR_FloatType<"FP128", "f128"> { } def CIR_LongDouble : CIR_FloatType<"LongDouble", "long_double"> { + let tbaaName = "long double"; let summary = "CIR extended-precision float type"; let description = [{ Floating-point type that represents the `long double` type in C/C++. @@ -241,7 +271,7 @@ def CIR_ComplexType : CIR_Type<"Complex", "complex", def CIR_PointerType : CIR_Type<"Pointer", "ptr", [DeclareTypeInterfaceMethods]> { - + let tbaaName = "any pointer"; let summary = "CIR pointer type"; let description = [{ `CIR.ptr` is a type returned by any op generating a pointer in C++. @@ -317,7 +347,7 @@ def CIR_DataMemberType : CIR_Type<"DataMember", "data_member", def CIR_BoolType : CIR_Type<"Bool", "bool", [DeclareTypeInterfaceMethods]> { - + let tbaaName = "bool"; let summary = "CIR bool type"; let description = [{ `cir.bool` represent's C++ bool type. @@ -609,4 +639,11 @@ def CIR_AnyType : AnyTypeOf<[ CIR_ComplexType ]>; +def CIR_AnyScalarType : AnyTypeOf<[ + CIR_IntType, CIR_PointerType, CIR_DataMemberType, CIR_MethodType, + CIR_BoolType, CIR_ArrayType, CIR_VectorType, CIR_FuncType, CIR_VoidType, + CIR_ExceptionType, CIR_AnyFloat, CIR_FP16, CIR_BFloat16, + CIR_ComplexType +]>; + #endif // MLIR_CIR_DIALECT_CIR_TYPES diff --git a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt index 3d43b06c6217..dc0afdd2bc31 100644 --- a/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt +++ b/clang/include/clang/CIR/Dialect/IR/CMakeLists.txt @@ -31,3 +31,7 @@ add_public_tablegen_target(MLIRCIREnumsGen) clang_tablegen(CIRBuiltinsLowering.inc -gen-cir-builtins-lowering SOURCE CIROps.td TARGET CIRBuiltinsLowering) + +clang_tablegen(CIRTBAANameLowering.inc -gen-cir-tbaa-name-lowering + SOURCE CIRTypes.td + TARGET CIRTBAANameLowering) diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index c0707d687fca..346719691a5d 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -58,7 +58,12 @@ struct MissingFeatures { // sanitizer related type check features static bool emitTypeCheck() { return false; } static bool tbaa() { return false; } - static bool tbaa_struct() { return false; } + static bool tbaaStruct() { return false; } + static bool tbaaTagForStruct() { return false; } + static bool tbaaVTablePtr() { return false; } + static bool tbaaIncompleteType() { return false; } + static bool tbaaMergeTBAAInfo() { return false; } + static bool tbaaMayAlias() { return false; } static bool cleanups() { return false; } static bool emitNullabilityCheck() { return false; } static bool ptrAuth() { return false; } diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h index 28be733f62d7..3019ca8ef62b 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h +++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h @@ -839,7 +839,7 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy { return create( loc, addr.getElementType(), addr.getPointer(), /*isDeref=*/false, /*is_volatile=*/isVolatile, /*alignment=*/mlir::IntegerAttr{}, - /*mem_order=*/cir::MemOrderAttr{}, /*tbaa=*/mlir::ArrayAttr{}); + /*mem_order=*/cir::MemOrderAttr{}, /*tbaa=*/cir::TBAAAttr{}); } mlir::Value createAlignedLoad(mlir::Location loc, mlir::Type ty, diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp index 4aec7747790c..83952d1dfae2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinAArch64.cpp @@ -2679,19 +2679,16 @@ static mlir::Value emitCommonNeonSISDBuiltinExpr( return emitNeonCall(builder, {argTy}, ops, "aarch64.neon.uaddlv", resultTy, loc); case NEON::BI__builtin_neon_vaddv_f32: - llvm_unreachable(" neon_vaddv_f32 NYI "); - case NEON::BI__builtin_neon_vaddv_s32: - llvm_unreachable(" neon_vaddv_s32 NYI "); - case NEON::BI__builtin_neon_vaddv_u32: - llvm_unreachable(" neon_vaddv_u32 NYI "); case NEON::BI__builtin_neon_vaddvq_f32: - llvm_unreachable(" neon_vaddvq_f32 NYI "); case NEON::BI__builtin_neon_vaddvq_f64: - llvm_unreachable(" neon_vaddvq_f64 NYI "); + return emitNeonCall(builder, {argTy}, ops, "aarch64.neon.faddv", resultTy, + loc); + case NEON::BI__builtin_neon_vaddv_s32: case NEON::BI__builtin_neon_vaddvq_s32: - llvm_unreachable(" neon_vaddvq_s32 NYI "); case NEON::BI__builtin_neon_vaddvq_s64: - llvm_unreachable(" neon_vaddvq_s64 NYI "); + return emitNeonCall(builder, {argTy}, ops, "aarch64.neon.saddv", resultTy, + loc); + case NEON::BI__builtin_neon_vaddv_u32: case NEON::BI__builtin_neon_vaddvq_u32: case NEON::BI__builtin_neon_vaddvq_u64: return emitNeonCall(builder, {argTy}, ops, "aarch64.neon.uaddv", resultTy, @@ -3924,8 +3921,15 @@ CIRGenFunction::emitAArch64BuiltinExpr(unsigned BuiltinID, const CallExpr *E, getLoc(E->getExprLoc())); } case NEON::BI__builtin_neon_vmax_v: - case NEON::BI__builtin_neon_vmaxq_v: - llvm_unreachable("NEON::BI__builtin_neon_vmaxq_v NYI"); + case NEON::BI__builtin_neon_vmaxq_v: { + mlir::Location loc = getLoc(E->getExprLoc()); + Ops[0] = builder.createBitcast(Ops[0], ty); + Ops[1] = builder.createBitcast(Ops[1], ty); + if (cir::isFPOrFPVectorTy(ty)) { + return builder.create(loc, Ops[0], Ops[1]); + } + return builder.create(loc, cir::BinOpKind::Max, Ops[0], Ops[1]); + } case NEON::BI__builtin_neon_vmaxh_f16: { llvm_unreachable("NEON::BI__builtin_neon_vmaxh_f16 NYI"); } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp b/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp index 46f89bf60d18..831e2e8c3ae6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp @@ -296,64 +296,7 @@ class AggExprEmitter : public StmtVisitor { void VisitCXXConstructExpr(const CXXConstructExpr *E); void VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E); void VisitLambdaExpr(LambdaExpr *E); - void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E) { - ASTContext &Ctx = CGF.getContext(); - CIRGenFunction::SourceLocRAIIObject locRAIIObject{ - CGF, CGF.getLoc(E->getSourceRange())}; - // Emit an array containing the elements. The array is externally - // destructed if the std::initializer_list object is. - LValue Array = CGF.emitLValue(E->getSubExpr()); - assert(Array.isSimple() && "initializer_list array not a simple lvalue"); - Address ArrayPtr = Array.getAddress(); - - const ConstantArrayType *ArrayType = - Ctx.getAsConstantArrayType(E->getSubExpr()->getType()); - assert(ArrayType && "std::initializer_list constructed from non-array"); - - RecordDecl *Record = E->getType()->castAs()->getDecl(); - RecordDecl::field_iterator Field = Record->field_begin(); - assert(Field != Record->field_end() && - Ctx.hasSameType(Field->getType()->getPointeeType(), - ArrayType->getElementType()) && - "Expected std::initializer_list first field to be const E *"); - // Start pointer. - auto loc = CGF.getLoc(E->getSourceRange()); - AggValueSlot Dest = EnsureSlot(loc, E->getType()); - LValue DestLV = CGF.makeAddrLValue(Dest.getAddress(), E->getType()); - LValue Start = - CGF.emitLValueForFieldInitialization(DestLV, *Field, Field->getName()); - mlir::Value ArrayStart = ArrayPtr.emitRawPointer(); - CGF.emitStoreThroughLValue(RValue::get(ArrayStart), Start); - ++Field; - assert(Field != Record->field_end() && - "Expected std::initializer_list to have two fields"); - - auto Builder = CGF.getBuilder(); - - auto sizeOp = Builder.getConstInt(loc, ArrayType->getSize()); - - mlir::Value Size = sizeOp.getRes(); - Builder.getUIntNTy(ArrayType->getSizeBitWidth()); - LValue EndOrLength = - CGF.emitLValueForFieldInitialization(DestLV, *Field, Field->getName()); - if (Ctx.hasSameType(Field->getType(), Ctx.getSizeType())) { - // Length. - CGF.emitStoreThroughLValue(RValue::get(Size), EndOrLength); - } else { - // End pointer. - assert(Field->getType()->isPointerType() && - Ctx.hasSameType(Field->getType()->getPointeeType(), - ArrayType->getElementType()) && - "Expected std::initializer_list second field to be const E *"); - - auto ArrayEnd = - Builder.getArrayElement(loc, loc, ArrayPtr.getPointer(), - ArrayPtr.getElementType(), Size, false); - CGF.emitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength); - } - assert(++Field == Record->field_end() && - "Expected std::initializer_list to only have two fields"); - } + void VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E); void VisitExprWithCleanups(ExprWithCleanups *E); void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) { @@ -954,6 +897,69 @@ void AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) { } } +void AggExprEmitter::VisitCXXStdInitializerListExpr( + CXXStdInitializerListExpr *E) { + ASTContext &Ctx = CGF.getContext(); + CIRGenFunction::SourceLocRAIIObject locRAIIObject{ + CGF, CGF.getLoc(E->getSourceRange())}; + // Emit an array containing the elements. The array is externally + // destructed if the std::initializer_list object is. + LValue Array = CGF.emitLValue(E->getSubExpr()); + assert(Array.isSimple() && "initializer_list array not a simple lvalue"); + Address ArrayPtr = Array.getAddress(); + + const ConstantArrayType *ArrayType = + Ctx.getAsConstantArrayType(E->getSubExpr()->getType()); + assert(ArrayType && "std::initializer_list constructed from non-array"); + + RecordDecl *Record = E->getType()->castAs()->getDecl(); + RecordDecl::field_iterator Field = Record->field_begin(); + assert(Field != Record->field_end() && + Ctx.hasSameType(Field->getType()->getPointeeType(), + ArrayType->getElementType()) && + "Expected std::initializer_list first field to be const E *"); + const FieldDecl *StartField = *Field; + ++Field; + assert(Field != Record->field_end() && + "Expected std::initializer_list to have two fields"); + const FieldDecl *EndOrLengthField = *Field; + ++Field; + assert(Field == Record->field_end() && + "Expected std::initializer_list to only have two fields"); + + // Start pointer. + auto loc = CGF.getLoc(E->getSourceRange()); + AggValueSlot Dest = EnsureSlot(loc, E->getType()); + LValue DestLV = CGF.makeAddrLValue(Dest.getAddress(), E->getType()); + LValue Start = CGF.emitLValueForFieldInitialization(DestLV, StartField, + StartField->getName()); + mlir::Value ArrayStart = ArrayPtr.emitRawPointer(); + CGF.emitStoreThroughLValue(RValue::get(ArrayStart), Start); + + auto Builder = CGF.getBuilder(); + + auto sizeOp = Builder.getConstInt(loc, ArrayType->getSize()); + + mlir::Value Size = sizeOp.getRes(); + LValue EndOrLength = CGF.emitLValueForFieldInitialization( + DestLV, EndOrLengthField, EndOrLengthField->getName()); + if (Ctx.hasSameType(EndOrLengthField->getType(), Ctx.getSizeType())) { + // Length. + CGF.emitStoreThroughLValue(RValue::get(Size), EndOrLength); + } else { + // End pointer. + assert(EndOrLengthField->getType()->isPointerType() && + Ctx.hasSameType(EndOrLengthField->getType()->getPointeeType(), + ArrayType->getElementType()) && + "Expected std::initializer_list second field to be const E *"); + + auto ArrayEnd = + Builder.getArrayElement(loc, loc, ArrayPtr.getPointer(), + ArrayPtr.getElementType(), Size, false); + CGF.emitStoreThroughLValue(RValue::get(ArrayEnd), EndOrLength); + } +} + void AggExprEmitter::VisitCastExpr(CastExpr *E) { if (const auto *ECE = dyn_cast(E)) CGF.CGM.emitExplicitCastExprType(ECE, &CGF); @@ -1716,7 +1722,7 @@ void CIRGenFunction::emitAggregateCopy(LValue Dest, LValue Src, QualType Ty, // Determine the metadata to describe the position of any padding in this // memcpy, as well as the TBAA tags for the members of the struct, in case // the optimizer wishes to expand it in to scalar memory operations. - assert(!cir::MissingFeatures::tbaa_struct() && "tbaa.struct NYI"); + assert(!cir::MissingFeatures::tbaaStruct() && "tbaa.struct NYI"); if (CGM.getCodeGenOpts().NewStructPathTBAA) { TBAAAccessInfo TBAAInfo = CGM.mergeTBAAInfoForMemoryTransfer( Dest.getTBAAInfo(), Src.getTBAAInfo()); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp index 50169aa849a4..068f060ca7c5 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp @@ -910,7 +910,7 @@ void CIRGenFunction::emitCXXDeleteExpr(const CXXDeleteExpr *E) { // we plan to handle it in LoweringPreparePass and the corresponding // ABI part. if (DeleteTy->isConstantArrayType()) { - Ptr = Ptr; + // Nothing to do here, keep it for skeleton comparison sake. } assert(convertTypeForMem(DeleteTy) == Ptr.getElementType()); diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index b7197afeb896..2a2557f1fdda 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -814,6 +814,13 @@ void CIRGenModule::replaceGlobal(cir::GlobalOp Old, cir::GlobalOp New) { auto UseOpResultValue = GGO.getAddr(); UseOpResultValue.setType( cir::PointerType::get(&getMLIRContext(), NewTy)); + + mlir::OpBuilder::InsertionGuard guard(builder); + builder.setInsertionPointAfter(UserOp); + mlir::Type ptrTy = builder.getPointerTo(OldTy); + mlir::Value cast = + builder.createBitcast(GGO->getLoc(), UseOpResultValue, ptrTy); + UseOpResultValue.replaceAllUsesExcept(cast, {cast.getDefiningOp()}); } } } @@ -3988,7 +3995,7 @@ cir::TBAAAttr CIRGenModule::getTBAABaseTypeInfo(QualType QTy) { return tbaa->getBaseTypeInfo(QTy); } -mlir::ArrayAttr CIRGenModule::getTBAAAccessTagInfo(TBAAAccessInfo tbaaInfo) { +cir::TBAAAttr CIRGenModule::getTBAAAccessTagInfo(TBAAAccessInfo tbaaInfo) { if (!tbaa) { return nullptr; } diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 905754a4ad3a..dd8a0c98b081 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -525,7 +525,7 @@ class CIRGenModule : public CIRGenTypeCache { /// type is not suitable for use in TBAA access tags. cir::TBAAAttr getTBAABaseTypeInfo(QualType QTy); - mlir::ArrayAttr getTBAAAccessTagInfo(TBAAAccessInfo tbaaInfo); + cir::TBAAAttr getTBAAAccessTagInfo(TBAAAccessInfo tbaaInfo); /// Get merged TBAA information for the purposes of type casts. TBAAAccessInfo mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo, diff --git a/clang/lib/CIR/CodeGen/CIRGenTBAA.cpp b/clang/lib/CIR/CodeGen/CIRGenTBAA.cpp index a6efc05e4110..ce2969d130ff 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTBAA.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenTBAA.cpp @@ -1,11 +1,12 @@ #include "CIRGenTBAA.h" -#include "CIRGenCXXABI.h" #include "CIRGenTypes.h" #include "mlir/IR/BuiltinAttributes.h" #include "mlir/IR/MLIRContext.h" #include "mlir/Interfaces/DataLayoutInterfaces.h" #include "clang/AST/ASTContext.h" #include "clang/AST/RecordLayout.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" +#include "clang/CIR/MissingFeatures.h" #include "llvm/Support/ErrorHandling.h" namespace clang::CIRGen { @@ -21,44 +22,159 @@ CIRGenTBAA::CIRGenTBAA(mlir::MLIRContext *mlirContext, : mlirContext(mlirContext), astContext(astContext), types(types), moduleOp(moduleOp), codeGenOpts(codeGenOpts), features(features) {} +cir::TBAAAttr CIRGenTBAA::getChar() { + return cir::TBAAScalarAttr::get(mlirContext, + cir::IntType::get(mlirContext, 1, true)); +} + +static bool typeHasMayAlias(clang::QualType qty) { + // Tagged types have declarations, and therefore may have attributes. + if (auto *td = qty->getAsTagDecl()) + if (td->hasAttr()) + return true; + + // Also look for may_alias as a declaration attribute on a typedef. + // FIXME: We should follow GCC and model may_alias as a type attribute + // rather than as a declaration attribute. + while (auto *tt = qty->getAs()) { + if (tt->getDecl()->hasAttr()) + return true; + qty = tt->desugar(); + } + return false; +} + +/// Check if the given type is a valid base type to be used in access tags. +static bool isValidBaseType(clang::QualType qty) { + if (const clang::RecordType *tty = qty->getAs()) { + const clang::RecordDecl *rd = tty->getDecl()->getDefinition(); + // Incomplete types are not valid base access types. + if (!rd) + return false; + if (rd->hasFlexibleArrayMember()) + return false; + // rd can be struct, union, class, interface or enum. + // For now, we only handle struct and class. + if (rd->isStruct() || rd->isClass()) + return true; + } + return false; +} + cir::TBAAAttr CIRGenTBAA::getTypeInfo(clang::QualType qty) { - return tbaa_NYI(mlirContext); + // At -O0 or relaxed aliasing, TBAA is not emitted for regular types. + if (codeGenOpts.OptimizationLevel == 0 || codeGenOpts.RelaxedAliasing) { + return nullptr; + } + + // If the type has the may_alias attribute (even on a typedef), it is + // effectively in the general char alias class. + if (typeHasMayAlias(qty)) { + assert(!cir::MissingFeatures::tbaaMayAlias()); + return getChar(); + } + // We need this function to not fall back to returning the "omnipotent char" + // type node for aggregate and union types. Otherwise, any dereference of an + // aggregate will result into the may-alias access descriptor, meaning all + // subsequent accesses to direct and indirect members of that aggregate will + // be considered may-alias too. + // function. + if (isValidBaseType(qty)) { + // TODO(cir): support TBAA with struct + return tbaa_NYI(mlirContext); + } + + const clang::Type *ty = astContext.getCanonicalType(qty).getTypePtr(); + if (metadataCache.contains(ty)) { + return metadataCache[ty]; + } + + // Note that the following helper call is allowed to add new nodes to the + // cache, which invalidates all its previously obtained iterators. So we + // first generate the node for the type and then add that node to the + // cache. + auto typeNode = cir::TBAAScalarAttr::get(mlirContext, types.ConvertType(qty)); + return metadataCache[ty] = typeNode; } TBAAAccessInfo CIRGenTBAA::getAccessInfo(clang::QualType accessType) { - return TBAAAccessInfo(); + // Pointee values may have incomplete types, but they shall never be + // dereferenced. + if (accessType->isIncompleteType()) { + assert(!cir::MissingFeatures::tbaaIncompleteType()); + return TBAAAccessInfo::getIncompleteInfo(); + } + + if (typeHasMayAlias(accessType)) { + assert(!cir::MissingFeatures::tbaaMayAlias()); + return TBAAAccessInfo::getMayAliasInfo(); + } + + uint64_t size = astContext.getTypeSizeInChars(accessType).getQuantity(); + return TBAAAccessInfo(getTypeInfo(accessType), size); } TBAAAccessInfo CIRGenTBAA::getVTablePtrAccessInfo(mlir::Type vtablePtrType) { + // TODO(cir): support vtable ptr + assert(!cir::MissingFeatures::tbaaVTablePtr()); return TBAAAccessInfo(); } mlir::ArrayAttr CIRGenTBAA::getTBAAStructInfo(clang::QualType qty) { - return mlir::ArrayAttr::get(mlirContext, {}); + assert(!cir::MissingFeatures::tbaaStruct() && "tbaa.struct NYI"); + return mlir::ArrayAttr(); } cir::TBAAAttr CIRGenTBAA::getBaseTypeInfo(clang::QualType qty) { return tbaa_NYI(mlirContext); } -mlir::ArrayAttr CIRGenTBAA::getAccessTagInfo(TBAAAccessInfo tbaaInfo) { - return mlir::ArrayAttr::get(mlirContext, {tbaa_NYI(mlirContext)}); +cir::TBAAAttr CIRGenTBAA::getAccessTagInfo(TBAAAccessInfo tbaaInfo) { + assert(!tbaaInfo.isIncomplete() && + "Access to an object of an incomplete type!"); + + if (tbaaInfo.isMayAlias()) { + assert(!cir::MissingFeatures::tbaaMayAlias()); + tbaaInfo = TBAAAccessInfo(getChar(), tbaaInfo.size); + } + if (!tbaaInfo.accessType) { + return nullptr; + } + + if (!codeGenOpts.StructPathTBAA) + tbaaInfo = TBAAAccessInfo(tbaaInfo.accessType, tbaaInfo.size); + + if (!tbaaInfo.baseType) { + tbaaInfo.baseType = tbaaInfo.accessType; + assert(!tbaaInfo.offset && + "Nonzero offset for an access with no base type!"); + } + if (codeGenOpts.NewStructPathTBAA) { + llvm_unreachable("NYI"); + } + if (tbaaInfo.baseType == tbaaInfo.accessType) { + return tbaaInfo.accessType; + } + return tbaa_NYI(mlirContext); } TBAAAccessInfo CIRGenTBAA::mergeTBAAInfoForCast(TBAAAccessInfo sourceInfo, TBAAAccessInfo targetInfo) { + assert(!cir::MissingFeatures::tbaaMergeTBAAInfo()); return TBAAAccessInfo(); } TBAAAccessInfo CIRGenTBAA::mergeTBAAInfoForConditionalOperator(TBAAAccessInfo infoA, TBAAAccessInfo infoB) { + assert(!cir::MissingFeatures::tbaaMergeTBAAInfo()); return TBAAAccessInfo(); } TBAAAccessInfo CIRGenTBAA::mergeTBAAInfoForMemoryTransfer(TBAAAccessInfo destInfo, TBAAAccessInfo srcInfo) { + assert(!cir::MissingFeatures::tbaaMergeTBAAInfo()); return TBAAAccessInfo(); } diff --git a/clang/lib/CIR/CodeGen/CIRGenTBAA.h b/clang/lib/CIR/CodeGen/CIRGenTBAA.h index 3f59a0e6538b..03b9b75113c9 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTBAA.h +++ b/clang/lib/CIR/CodeGen/CIRGenTBAA.h @@ -104,6 +104,10 @@ class CIRGenTBAA { [[maybe_unused]] const clang::CodeGenOptions &codeGenOpts; [[maybe_unused]] const clang::LangOptions &features; + llvm::DenseMap metadataCache; + + cir::TBAAAttr getChar(); + public: CIRGenTBAA(mlir::MLIRContext *mlirContext, clang::ASTContext &astContext, CIRGenTypes &types, mlir::ModuleOp moduleOp, @@ -129,7 +133,7 @@ class CIRGenTBAA { cir::TBAAAttr getBaseTypeInfo(clang::QualType qty); /// Get TBAA tag for a given memory access. - mlir::ArrayAttr getAccessTagInfo(TBAAAccessInfo tbaaInfo); + cir::TBAAAttr getAccessTagInfo(TBAAAccessInfo tbaaInfo); /// Get merged TBAA information for the purpose of type casts. TBAAAccessInfo mergeTBAAInfoForCast(TBAAAccessInfo sourceInfo, diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 1c5a6467f538..242afd4f00b8 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -17,6 +17,7 @@ #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/Interfaces/CIRLoopOpInterface.h" #include "clang/CIR/MissingFeatures.h" +#include "llvm/ADT/TypeSwitch.h" #include "llvm/Support/ErrorHandling.h" #include #include @@ -106,12 +107,12 @@ struct CIROpAsmDialectInterface : public OpAsmDialectInterface { os << dynCastInfoAttr.getAlias(); return AliasResult::FinalAlias; } - if (auto tbaaAttr = mlir::dyn_cast(attr)) { - os << tbaaAttr.getMnemonic(); - return AliasResult::OverridableAlias; - } - - return AliasResult::NoAlias; + return TypeSwitch(attr) + .Case([&](auto attr) { + os << decltype(attr)::getMnemonic(); + return AliasResult::OverridableAlias; + }) + .Default([](Attribute) { return AliasResult::NoAlias; }); } }; } // namespace diff --git a/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp b/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp index 80963353a304..bb99d53e0ad8 100644 --- a/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRMemorySlot.cpp @@ -151,7 +151,7 @@ DeletionKind cir::CopyOp::removeBlockingUses( if (loadsFrom(slot)) builder.create(getLoc(), reachingDefinition, getDst(), false, mlir::IntegerAttr{}, cir::MemOrderAttr(), - mlir::ArrayAttr{}); + cir::TBAAAttr{}); return DeletionKind::Delete; } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index c933035cd850..a6ff22f3b7de 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -18,6 +18,7 @@ #include "mlir/Conversion/SCFToControlFlow/SCFToControlFlow.h" #include "mlir/Dialect/DLTI/DLTI.h" #include "mlir/Dialect/Func/IR/FuncOps.h" +#include "mlir/Dialect/LLVMIR/LLVMAttrs.h" #include "mlir/Dialect/LLVMIR/Transforms/Passes.h" #include "mlir/IR/Attributes.h" #include "mlir/IR/Builders.h" @@ -41,6 +42,9 @@ #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.h" #include "mlir/Target/LLVMIR/Export.h" +#include "clang/CIR/Dialect/IR/CIRAttrs.h" +#include "clang/CIR/Dialect/IR/CIRDialect.h" +#include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/Dialect/Passes.h" #include "clang/CIR/LoweringHelpers.h" #include "clang/CIR/MissingFeatures.h" @@ -51,6 +55,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/ADT/TypeSwitch.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/Support/Casting.h" @@ -666,6 +671,66 @@ mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp, mlir::Attribute attr, llvm_unreachable("unhandled attribute type"); } +mlir::LLVM::TBAATypeDescriptorAttr +createScalarTypeNode(mlir::MLIRContext *ctx, llvm::StringRef typeName, + mlir::LLVM::TBAANodeAttr parent, int64_t offset) { + llvm::SmallVector members; + members.push_back(mlir::LLVM::TBAAMemberAttr::get(ctx, parent, offset)); + return mlir::LLVM::TBAATypeDescriptorAttr::get( + ctx, typeName, llvm::ArrayRef(members)); +} + +mlir::LLVM::TBAARootAttr getRoot(mlir::MLIRContext *ctx) { + return mlir::LLVM::TBAARootAttr::get( + ctx, mlir::StringAttr::get(ctx, "Simple C/C++ TBAA")); +} + +mlir::LLVM::TBAATypeDescriptorAttr getChar(mlir::MLIRContext *ctx) { + return createScalarTypeNode(ctx, "omnipotent char", getRoot(ctx), 0); +} + +#define GET_TBAANAME_LOWERING_FUNCTIONS_DEF +#include "clang/CIR/Dialect/IR/CIRTBAANameLowering.inc" +#undef GET_TBAANAME_LOWERING_FUNCTIONS_DEF + +StringRef getTypeName(mlir::Type type) { + return TypeSwitch(type) + .Case([](cir::IntType ty) { return ty.getTBAATypeName(); }) + .Case< +#define GET_TBAANAME_LOWERING_LIST +#include "clang/CIR/Dialect/IR/CIRTBAANameLowering.inc" +#undef GET_TBAANAME_LOWERING_LIST + >([](auto ty) { return getTBAAName(ty); }) + .Default([](auto ty) { + llvm::errs() << "unknown type: " << ty << "\n"; + return "unknown"; + }); +} + +mlir::LLVM::TBAATypeDescriptorAttr +lowerScalarType(mlir::MLIRContext *ctx, cir::TBAAScalarAttr scalarAttr) { + // special handle for omnipotent char + if (auto intTy = mlir::dyn_cast_or_null(scalarAttr.getType())) { + if (intTy.getWidth() == 1 || intTy.getWidth() == 8) { + return getChar(ctx); + } + } + auto name = getTypeName(scalarAttr.getType()); + return createScalarTypeNode(ctx, name, getChar(ctx), 0); +} + +mlir::ArrayAttr lowerCIRTBAAAttr(mlir::Attribute tbaa, + mlir::ConversionPatternRewriter &rewriter) { + auto *ctx = rewriter.getContext(); + if (auto scalarAttr = mlir::dyn_cast(tbaa)) { + auto accessType = lowerScalarType(ctx, scalarAttr); + auto tag = mlir::LLVM::TBAATagAttr::get(accessType, accessType, 0); + return mlir::ArrayAttr::get(ctx, {tag}); + } + assert(!cir::MissingFeatures::tbaaTagForStruct()); + return mlir::ArrayAttr(); +} + //===----------------------------------------------------------------------===// mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage) { @@ -1512,10 +1577,14 @@ mlir::LogicalResult CIRToLLVMLoadOpLowering::matchAndRewrite( } // TODO: nontemporal, syncscope. - rewriter.replaceOpWithNewOp( - op, llvmTy, adaptor.getAddr(), /* alignment */ alignment, + auto loadOp = rewriter.create( + op->getLoc(), llvmTy, adaptor.getAddr(), /* alignment */ alignment, op.getIsVolatile(), /* nontemporal */ false, /* invariant */ false, /* invariantGroup */ invariant, ordering); + rewriter.replaceOp(op, loadOp); + if (auto tbaa = op.getTbaaAttr()) { + loadOp.setTBAATags(lowerCIRTBAAAttr(tbaa, rewriter)); + } return mlir::LogicalResult::success(); } @@ -1547,9 +1616,14 @@ mlir::LogicalResult CIRToLLVMStoreOpLowering::matchAndRewrite( } // TODO: nontemporal, syncscope. - rewriter.replaceOpWithNewOp( - op, adaptor.getValue(), adaptor.getAddr(), alignment, op.getIsVolatile(), + auto storeOp = rewriter.create( + op->getLoc(), adaptor.getValue(), adaptor.getAddr(), alignment, + op.getIsVolatile(), /* nontemporal */ false, /* invariantGroup */ invariant, ordering); + rewriter.replaceOp(op, storeOp); + if (auto tbaa = op.getTbaaAttr()) { + storeOp.setTBAATags(lowerCIRTBAAAttr(tbaa, rewriter)); + } return mlir::LogicalResult::success(); } diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h index 48baae2ae799..2b05f51309c5 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h @@ -1099,5 +1099,9 @@ class CIRToLLVMSignBitOpLowering #include "clang/CIR/Dialect/IR/CIRBuiltinsLowering.inc" #undef GET_BUILTIN_LOWERING_CLASSES_DECLARE +#define GET_TBAANAME_LOWERING_FUNCTIONS_DECLARE +#include "clang/CIR/Dialect/IR/CIRTBAANameLowering.inc" +#undef GET_TBAANAME_LOWERING_FUNCTIONS_DECLARE + } // namespace direct } // namespace cir diff --git a/clang/test/CIR/CodeGen/AArch64/neon-arith.c b/clang/test/CIR/CodeGen/AArch64/neon-arith.c index b04b9ecb06d1..92a97831d52a 100644 --- a/clang/test/CIR/CodeGen/AArch64/neon-arith.c +++ b/clang/test/CIR/CodeGen/AArch64/neon-arith.c @@ -952,3 +952,27 @@ uint64_t test_vaddvq_u64(uint64x2_t a) { // LLVM: [[VADDVQ_U64_I:%.*]] = call i64 @llvm.aarch64.neon.uaddv.i64.v2i64(<2 x i64> {{%.*}}) // LLVM: ret i64 [[VADDVQ_U64_I]] } + +int32_t test_vaddvq_s32(int32x4_t a) { + return vaddvq_s32(a); + + // CIR-LABEL: vaddvq_s32 + // CIR: cir.llvm.intrinsic "aarch64.neon.saddv" {{%.*}} : (!cir.vector) -> !s32i + + // LLVM-LABEL: test_vaddvq_s32 + // LLVM-SAME: (<4 x i32> [[a:%.*]]) + // LLVM: [[VADDVQ_S32_I:%.*]] = call i32 @llvm.aarch64.neon.saddv.i32.v4i32(<4 x i32> [[a]]) + // LLVM: ret i32 [[VADDVQ_S32_I]] +} + +int64_t test_vaddvq_s64(int64x2_t a) { + return vaddvq_s64(a); + + // CIR-LABEL: vaddvq_s64 + // CIR: cir.llvm.intrinsic "aarch64.neon.saddv" {{%.*}} : (!cir.vector) -> !s64i + + // LLVM-LABEL: test_vaddvq_s64 + // LLVM-SAME: (<2 x i64> [[a:%.*]]) + // LLVM: [[VADDVQ_S64_I:%.*]] = call i64 @llvm.aarch64.neon.saddv.i64.v2i64(<2 x i64> [[a]]) + // LLVM: ret i64 [[VADDVQ_S64_I]] +} diff --git a/clang/test/CIR/CodeGen/AArch64/neon.c b/clang/test/CIR/CodeGen/AArch64/neon.c index 06cc61a7c91e..1abc935f95b0 100644 --- a/clang/test/CIR/CodeGen/AArch64/neon.c +++ b/clang/test/CIR/CodeGen/AArch64/neon.c @@ -4270,132 +4270,207 @@ uint64x2_t test_vrshlq_u64(uint64x2_t a, int64x2_t b) { // return vsliq_n_p64(a, b, 0); // } -// NYI-LABEL: @test_vmax_s8( -// NYI: [[VMAX_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.smax.v8i8(<8 x i8> %a, <8 x i8> %b) -// NYI: ret <8 x i8> [[VMAX_I]] -// int8x8_t test_vmax_s8(int8x8_t a, int8x8_t b) { -// return vmax_s8(a, b); -// } +int8x8_t test_vmax_s8(int8x8_t a, int8x8_t b) { + return vmax_s8(a, b); -// NYI-LABEL: @test_vmax_s16( -// NYI: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8> -// NYI: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8> -// NYI: [[VMAX2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.smax.v4i16(<4 x i16> %a, <4 x i16> %b) -// NYI: ret <4 x i16> [[VMAX2_I]] -// int16x4_t test_vmax_s16(int16x4_t a, int16x4_t b) { -// return vmax_s16(a, b); -// } + // CIR-LABEL: vmax_s8 + // CIR: cir.binop(max, {{%.*}}, {{%.*}}) : !cir.vector -// NYI-LABEL: @test_vmax_s32( -// NYI: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8> -// NYI: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8> -// NYI: [[VMAX2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.smax.v2i32(<2 x i32> %a, <2 x i32> %b) -// NYI: ret <2 x i32> [[VMAX2_I]] -// int32x2_t test_vmax_s32(int32x2_t a, int32x2_t b) { -// return vmax_s32(a, b); -// } + // LLVM-LABEL: test_vmax_s8 + // LLVM-SAME: (<8 x i8> [[a:%.*]], <8 x i8> [[b:%.*]]) + // LLVM: [[VMAX_I:%.*]] = call <8 x i8> @llvm.smax.v8i8(<8 x i8> [[a]], <8 x i8> [[b]]) + // LLVM: ret <8 x i8> [[VMAX_I]] +} -// NYI-LABEL: @test_vmax_u8( -// NYI: [[VMAX_I:%.*]] = call <8 x i8> @llvm.aarch64.neon.umax.v8i8(<8 x i8> %a, <8 x i8> %b) -// NYI: ret <8 x i8> [[VMAX_I]] -// uint8x8_t test_vmax_u8(uint8x8_t a, uint8x8_t b) { -// return vmax_u8(a, b); -// } +int16x4_t test_vmax_s16(int16x4_t a, int16x4_t b) { + return vmax_s16(a, b); -// NYI-LABEL: @test_vmax_u16( -// NYI: [[TMP0:%.*]] = bitcast <4 x i16> %a to <8 x i8> -// NYI: [[TMP1:%.*]] = bitcast <4 x i16> %b to <8 x i8> -// NYI: [[VMAX2_I:%.*]] = call <4 x i16> @llvm.aarch64.neon.umax.v4i16(<4 x i16> %a, <4 x i16> %b) -// NYI: ret <4 x i16> [[VMAX2_I]] -// uint16x4_t test_vmax_u16(uint16x4_t a, uint16x4_t b) { -// return vmax_u16(a, b); -// } + // CIR-LABEL: vmax_s16 + // CIR: cir.binop(max, {{%.*}}, {{%.*}}) : !cir.vector -// NYI-LABEL: @test_vmax_u32( -// NYI: [[TMP0:%.*]] = bitcast <2 x i32> %a to <8 x i8> -// NYI: [[TMP1:%.*]] = bitcast <2 x i32> %b to <8 x i8> -// NYI: [[VMAX2_I:%.*]] = call <2 x i32> @llvm.aarch64.neon.umax.v2i32(<2 x i32> %a, <2 x i32> %b) -// NYI: ret <2 x i32> [[VMAX2_I]] -// uint32x2_t test_vmax_u32(uint32x2_t a, uint32x2_t b) { -// return vmax_u32(a, b); -// } + // LLVM-LABEL: test_vmax_s16 + // LLVM-SAME: (<4 x i16> [[a:%.*]], <4 x i16> [[b:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <4 x i16> [[a]] to <8 x i8> + // LLVM: [[TMP1:%.*]] = bitcast <4 x i16> [[b]] to <8 x i8> + // LLVM: [[VMAX2_I:%.*]] = call <4 x i16> @llvm.smax.v4i16(<4 x i16> [[a]], <4 x i16> [[b]]) + // LLVM: ret <4 x i16> [[VMAX2_I]] +} -// NYI-LABEL: @test_vmax_f32( -// NYI: [[TMP0:%.*]] = bitcast <2 x float> %a to <8 x i8> -// NYI: [[TMP1:%.*]] = bitcast <2 x float> %b to <8 x i8> -// NYI: [[VMAX2_I:%.*]] = call <2 x float> @llvm.aarch64.neon.fmax.v2f32(<2 x float> %a, <2 x float> %b) -// NYI: ret <2 x float> [[VMAX2_I]] -// float32x2_t test_vmax_f32(float32x2_t a, float32x2_t b) { -// return vmax_f32(a, b); -// } +int32x2_t test_vmax_s32(int32x2_t a, int32x2_t b) { + return vmax_s32(a, b); -// NYI-LABEL: @test_vmaxq_s8( -// NYI: [[VMAX_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.smax.v16i8(<16 x i8> %a, <16 x i8> %b) -// NYI: ret <16 x i8> [[VMAX_I]] -// int8x16_t test_vmaxq_s8(int8x16_t a, int8x16_t b) { -// return vmaxq_s8(a, b); -// } + // CIR-LABEL: vmax_s32 + // CIR: cir.binop(max, {{%.*}}, {{%.*}}) : !cir.vector -// NYI-LABEL: @test_vmaxq_s16( -// NYI: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8> -// NYI: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8> -// NYI: [[VMAX2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.smax.v8i16(<8 x i16> %a, <8 x i16> %b) -// NYI: ret <8 x i16> [[VMAX2_I]] -// int16x8_t test_vmaxq_s16(int16x8_t a, int16x8_t b) { -// return vmaxq_s16(a, b); -// } + // LLVM-LABEL: test_vmax_s32 + // LLVM-SAME: (<2 x i32> [[a:%.*]], <2 x i32> [[b:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <2 x i32> [[a]] to <8 x i8> + // LLVM: [[TMP1:%.*]] = bitcast <2 x i32> [[b]] to <8 x i8> + // LLVM: [[VMAX2_I:%.*]] = call <2 x i32> @llvm.smax.v2i32(<2 x i32> [[a]], <2 x i32> [[b]]) + // LLVM: ret <2 x i32> [[VMAX2_I]] +} -// NYI-LABEL: @test_vmaxq_s32( -// NYI: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8> -// NYI: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8> -// NYI: [[VMAX2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.smax.v4i32(<4 x i32> %a, <4 x i32> %b) -// NYI: ret <4 x i32> [[VMAX2_I]] -// int32x4_t test_vmaxq_s32(int32x4_t a, int32x4_t b) { -// return vmaxq_s32(a, b); -// } +uint8x8_t test_vmax_u8(uint8x8_t a, uint8x8_t b) { + return vmax_u8(a, b); -// NYI-LABEL: @test_vmaxq_u8( -// NYI: [[VMAX_I:%.*]] = call <16 x i8> @llvm.aarch64.neon.umax.v16i8(<16 x i8> %a, <16 x i8> %b) -// NYI: ret <16 x i8> [[VMAX_I]] -// uint8x16_t test_vmaxq_u8(uint8x16_t a, uint8x16_t b) { -// return vmaxq_u8(a, b); -// } + // CIR-LABEL: vmax_u8 + // CIR: cir.binop(max, {{%.*}}, {{%.*}}) : !cir.vector -// NYI-LABEL: @test_vmaxq_u16( -// NYI: [[TMP0:%.*]] = bitcast <8 x i16> %a to <16 x i8> -// NYI: [[TMP1:%.*]] = bitcast <8 x i16> %b to <16 x i8> -// NYI: [[VMAX2_I:%.*]] = call <8 x i16> @llvm.aarch64.neon.umax.v8i16(<8 x i16> %a, <8 x i16> %b) -// NYI: ret <8 x i16> [[VMAX2_I]] -// uint16x8_t test_vmaxq_u16(uint16x8_t a, uint16x8_t b) { -// return vmaxq_u16(a, b); -// } + // LLVM-LABEL: test_vmax_u8 + // LLVM-SAME: (<8 x i8> [[a:%.*]], <8 x i8> [[b:%.*]]) + // LLVM: [[VMAX_I:%.*]] = call <8 x i8> @llvm.umax.v8i8(<8 x i8> [[a]], <8 x i8> [[b]]) + // LLVM: ret <8 x i8> [[VMAX_I]] +} -// NYI-LABEL: @test_vmaxq_u32( -// NYI: [[TMP0:%.*]] = bitcast <4 x i32> %a to <16 x i8> -// NYI: [[TMP1:%.*]] = bitcast <4 x i32> %b to <16 x i8> -// NYI: [[VMAX2_I:%.*]] = call <4 x i32> @llvm.aarch64.neon.umax.v4i32(<4 x i32> %a, <4 x i32> %b) -// NYI: ret <4 x i32> [[VMAX2_I]] -// uint32x4_t test_vmaxq_u32(uint32x4_t a, uint32x4_t b) { -// return vmaxq_u32(a, b); -// } +uint16x4_t test_vmax_u16(uint16x4_t a, uint16x4_t b) { + return vmax_u16(a, b); -// NYI-LABEL: @test_vmaxq_f32( -// NYI: [[TMP0:%.*]] = bitcast <4 x float> %a to <16 x i8> -// NYI: [[TMP1:%.*]] = bitcast <4 x float> %b to <16 x i8> -// NYI: [[VMAX2_I:%.*]] = call <4 x float> @llvm.aarch64.neon.fmax.v4f32(<4 x float> %a, <4 x float> %b) -// NYI: ret <4 x float> [[VMAX2_I]] -// float32x4_t test_vmaxq_f32(float32x4_t a, float32x4_t b) { -// return vmaxq_f32(a, b); -// } + // CIR-LABEL: vmax_u16 + // CIR: cir.binop(max, {{%.*}}, {{%.*}}) : !cir.vector -// NYI-LABEL: @test_vmaxq_f64( -// NYI: [[TMP0:%.*]] = bitcast <2 x double> %a to <16 x i8> -// NYI: [[TMP1:%.*]] = bitcast <2 x double> %b to <16 x i8> -// NYI: [[VMAX2_I:%.*]] = call <2 x double> @llvm.aarch64.neon.fmax.v2f64(<2 x double> %a, <2 x double> %b) -// NYI: ret <2 x double> [[VMAX2_I]] -// float64x2_t test_vmaxq_f64(float64x2_t a, float64x2_t b) { -// return vmaxq_f64(a, b); -// } + // LLVM-LABEL: test_vmax_u16 + // LLVM-SAME: (<4 x i16> [[a:%.*]], <4 x i16> [[b:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <4 x i16> [[a]] to <8 x i8> + // LLVM: [[TMP1:%.*]] = bitcast <4 x i16> [[b]] to <8 x i8> + // LLVM: [[VMAX2_I:%.*]] = call <4 x i16> @llvm.umax.v4i16(<4 x i16> [[a]], <4 x i16> [[b]]) + // LLVM: ret <4 x i16> [[VMAX2_I]] +} + +uint32x2_t test_vmax_u32(uint32x2_t a, uint32x2_t b) { + return vmax_u32(a, b); + + // CIR-LABEL: vmax_u32 + // CIR: cir.binop(max, {{%.*}}, {{%.*}}) : !cir.vector + + // LLVM-LABEL: test_vmax_u32 + // LLVM-SAME: (<2 x i32> [[a:%.*]], <2 x i32> [[b:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <2 x i32> [[a]] to <8 x i8> + // LLVM: [[TMP1:%.*]] = bitcast <2 x i32> [[b]] to <8 x i8> + // LLVM: [[VMAX2_I:%.*]] = call <2 x i32> @llvm.umax.v2i32(<2 x i32> [[a]], <2 x i32> [[b]]) + // LLVM: ret <2 x i32> [[VMAX2_I]] +} + +float32x2_t test_vmax_f32(float32x2_t a, float32x2_t b) { + return vmax_f32(a, b); + + // CIR-LABEL: vmax_f32 + // CIR: cir.fmaximum {{%.*}}, {{%.*}} : !cir.vector + + // LLVM-LABEL: test_vmax_f32 + // LLVM-SAME: (<2 x float> [[a:%.*]], <2 x float> [[b:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <2 x float> [[a]] to <8 x i8> + // LLVM: [[TMP1:%.*]] = bitcast <2 x float> [[b]] to <8 x i8> + // LLVM: [[VMAX2_I:%.*]] = call <2 x float> @llvm.maximum.v2f32(<2 x float> [[a]], <2 x float> [[b]]) + // LLVM: ret <2 x float> [[VMAX2_I]] +} + +int8x16_t test_vmaxq_s8(int8x16_t a, int8x16_t b) { + return vmaxq_s8(a, b); + + // CIR-LABEL: vmaxq_s8 + // CIR: cir.binop(max, {{%.*}}, {{%.*}}) : !cir.vector + + // LLVM-LABEL: test_vmaxq_s8 + // LLVM-SAME: (<16 x i8> [[a:%.*]], <16 x i8> [[b:%.*]]) + // LLVM: [[VMAX_I:%.*]] = call <16 x i8> @llvm.smax.v16i8(<16 x i8> [[a]], <16 x i8> [[b]]) + // LLVM: ret <16 x i8> [[VMAX_I]] +} + +int16x8_t test_vmaxq_s16(int16x8_t a, int16x8_t b) { + return vmaxq_s16(a, b); + + // CIR-LABEL: vmaxq_s16 + // CIR: cir.binop(max, {{%.*}}, {{%.*}}) : !cir.vector + + // LLVM-LABEL: test_vmaxq_s16 + // LLVM-SAME: (<8 x i16> [[a:%.*]], <8 x i16> [[b:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[a]] to <16 x i8> + // LLVM: [[TMP1:%.*]] = bitcast <8 x i16> [[b]] to <16 x i8> + // LLVM: [[VMAX2_I:%.*]] = call <8 x i16> @llvm.smax.v8i16(<8 x i16> [[a]], <8 x i16> [[b]]) + // LLVM: ret <8 x i16> [[VMAX2_I]] +} + +int32x4_t test_vmaxq_s32(int32x4_t a, int32x4_t b) { + return vmaxq_s32(a, b); + + // CIR-LABEL: vmaxq_s32 + // CIR: cir.binop(max, {{%.*}}, {{%.*}}) : !cir.vector + + // LLVM-LABEL: test_vmaxq_s32 + // LLVM-SAME: (<4 x i32> [[a:%.*]], <4 x i32> [[b:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[a]] to <16 x i8> + // LLVM: [[TMP1:%.*]] = bitcast <4 x i32> [[b]] to <16 x i8> + // LLVM: [[VMAX2_I:%.*]] = call <4 x i32> @llvm.smax.v4i32(<4 x i32> [[a]], <4 x i32> [[b]]) + // LLVM: ret <4 x i32> [[VMAX2_I]] +} + +uint8x16_t test_vmaxq_u8(uint8x16_t a, uint8x16_t b) { + return vmaxq_u8(a, b); + + // CIR-LABEL: vmaxq_u8 + // CIR: cir.binop(max, {{%.*}}, {{%.*}}) : !cir.vector + + // LLVM-LABEL: test_vmaxq_u8 + // LLVM-SAME: (<16 x i8> [[a:%.*]], <16 x i8> [[b:%.*]]) + // LLVM: [[VMAX_I:%.*]] = call <16 x i8> @llvm.umax.v16i8(<16 x i8> [[a]], <16 x i8> [[b]]) + // LLVM: ret <16 x i8> [[VMAX_I]] +} + +uint16x8_t test_vmaxq_u16(uint16x8_t a, uint16x8_t b) { + return vmaxq_u16(a, b); + + // CIR-LABEL: vmaxq_u16 + // CIR: cir.binop(max, {{%.*}}, {{%.*}}) : !cir.vector + + // LLVM-LABEL: test_vmaxq_u16 + // LLVM-SAME: (<8 x i16> [[a:%.*]], <8 x i16> [[b:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <8 x i16> [[a]] to <16 x i8> + // LLVM: [[TMP1:%.*]] = bitcast <8 x i16> [[b]] to <16 x i8> + // LLVM: [[VMAX2_I:%.*]] = call <8 x i16> @llvm.umax.v8i16(<8 x i16> [[a]], <8 x i16> [[b]]) + // LLVM: ret <8 x i16> [[VMAX2_I]] +} + +uint32x4_t test_vmaxq_u32(uint32x4_t a, uint32x4_t b) { + return vmaxq_u32(a, b); + + // CIR-LABEL: vmaxq_u32 + // CIR: cir.binop(max, {{%.*}}, {{%.*}}) : !cir.vector + + // LLVM-LABEL: test_vmaxq_u32 + // LLVM-SAME: (<4 x i32> [[a:%.*]], <4 x i32> [[b:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <4 x i32> [[a]] to <16 x i8> + // LLVM: [[TMP1:%.*]] = bitcast <4 x i32> [[b]] to <16 x i8> + // LLVM: [[VMAX2_I:%.*]] = call <4 x i32> @llvm.umax.v4i32(<4 x i32> [[a]], <4 x i32> [[b]]) + // LLVM: ret <4 x i32> [[VMAX2_I]] +} + +float32x4_t test_vmaxq_f32(float32x4_t a, float32x4_t b) { + return vmaxq_f32(a, b); + + // CIR-LABEL: vmaxq_f32 + // CIR: cir.fmaximum {{%.*}}, {{%.*}} : !cir.vector + + // LLVM-LABEL: test_vmaxq_f32 + // LLVM-SAME: (<4 x float> [[a:%.*]], <4 x float> [[b:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <4 x float> [[a]] to <16 x i8> + // LLVM: [[TMP1:%.*]] = bitcast <4 x float> [[b]] to <16 x i8> + // LLVM: [[VMAX2_I:%.*]] = call <4 x float> @llvm.maximum.v4f32(<4 x float> [[a]], <4 x float> [[b]]) + // LLVM: ret <4 x float> [[VMAX2_I]] +} + +float64x2_t test_vmaxq_f64(float64x2_t a, float64x2_t b) { + return vmaxq_f64(a, b); + + // CIR-LABEL: vmaxq_f64 + // CIR: cir.fmaximum {{%.*}}, {{%.*}} : !cir.vector + + // LLVM-LABEL: test_vmaxq_f64 + // LLVM-SAME: (<2 x double> [[a:%.*]], <2 x double> [[b:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <2 x double> [[a]] to <16 x i8> + // LLVM: [[TMP1:%.*]] = bitcast <2 x double> [[b]] to <16 x i8> + // LLVM: [[VMAX2_I:%.*]] = call <2 x double> @llvm.maximum.v2f64(<2 x double> [[a]], <2 x double> [[b]]) + // LLVM: ret <2 x double> [[VMAX2_I]] +} int8x8_t test_vmin_s8(int8x8_t a, int8x8_t b) { return vmin_s8(a, b); @@ -18383,26 +18458,41 @@ uint64x1_t test_vrsra_n_u64(uint64x1_t a, uint64x1_t b) { // return vneg_s64(a); // } -// NYI-LABEL: @test_vaddv_f32( -// NYI: [[VADDV_F32_I:%.*]] = call float @llvm.aarch64.neon.faddv.f32.v2f32(<2 x float> %a) -// NYI: ret float [[VADDV_F32_I]] -// float32_t test_vaddv_f32(float32x2_t a) { -// return vaddv_f32(a); -// } +float32_t test_vaddv_f32(float32x2_t a) { + return vaddv_f32(a); -// NYI-LABEL: @test_vaddvq_f32( -// NYI: [[VADDVQ_F32_I:%.*]] = call float @llvm.aarch64.neon.faddv.f32.v4f32(<4 x float> %a) -// NYI: ret float [[VADDVQ_F32_I]] -// float32_t test_vaddvq_f32(float32x4_t a) { -// return vaddvq_f32(a); -// } + // CIR-LABEL: vaddv_f32 + // CIR: cir.llvm.intrinsic "aarch64.neon.faddv" {{%.*}} : (!cir.vector) -> !cir.float -// NYI-LABEL: @test_vaddvq_f64( -// NYI: [[VADDVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.faddv.f64.v2f64(<2 x double> %a) -// NYI: ret double [[VADDVQ_F64_I]] -// float64_t test_vaddvq_f64(float64x2_t a) { -// return vaddvq_f64(a); -// } + // LLVM-LABEL: test_vaddv_f32 + // LLVM-SAME: (<2 x float> [[a:%.*]]) + // LLVM: [[VADDV_F32_I:%.*]] = call float @llvm.aarch64.neon.faddv.f32.v2f32(<2 x float> [[a]]) + // LLVM: ret float [[VADDV_F32_I]] +} + +float32_t test_vaddvq_f32(float32x4_t a) { + return vaddvq_f32(a); + + // CIR-LABEL: vaddvq_f32 + // CIR: cir.llvm.intrinsic "aarch64.neon.faddv" {{%.*}} : (!cir.vector) -> !cir.float + + // LLVM-LABEL: test_vaddvq_f32 + // LLVM-SAME: (<4 x float> [[a:%.*]]) + // LLVM: [[VADDVQ_F32_I:%.*]] = call float @llvm.aarch64.neon.faddv.f32.v4f32(<4 x float> [[a]]) + // LLVM: ret float [[VADDVQ_F32_I]] +} + +float64_t test_vaddvq_f64(float64x2_t a) { + return vaddvq_f64(a); + + // CIR-LABEL: vaddvq_f64 + // CIR: cir.llvm.intrinsic "aarch64.neon.faddv" {{%.*}} : (!cir.vector) -> !cir.double + + // LLVM-LABEL: test_vaddvq_f64 + // LLVM-SAME: (<2 x double> [[a:%.*]]) + // LLVM: [[VADDVQ_F64_I:%.*]] = call double @llvm.aarch64.neon.faddv.f64.v2f64(<2 x double> [[a]]) + // LLVM: ret double [[VADDVQ_F64_I]] +} // NYI-LABEL: @test_vmaxv_f32( // NYI: [[VMAXV_F32_I:%.*]] = call float @llvm.aarch64.neon.fmaxv.f32.v2f32(<2 x float> %a) @@ -18571,14 +18661,19 @@ uint64x1_t test_vrsra_n_u64(uint64x1_t a, uint64x1_t b) { // return vabd_f64(a, b); // } -// NYI-LABEL: @test_vmax_f64( -// NYI: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8> -// NYI: [[TMP1:%.*]] = bitcast <1 x double> %b to <8 x i8> -// NYI: [[VMAX2_I:%.*]] = call <1 x double> @llvm.aarch64.neon.fmax.v1f64(<1 x double> %a, <1 x double> %b) -// NYI: ret <1 x double> [[VMAX2_I]] -// float64x1_t test_vmax_f64(float64x1_t a, float64x1_t b) { -// return vmax_f64(a, b); -// } +float64x1_t test_vmax_f64(float64x1_t a, float64x1_t b) { + return vmax_f64(a, b); + + // CIR-LABEL: vmax_f64 + // CIR: cir.fmaximum {{%.*}}, {{%.*}} : !cir.vector + + // LLVM-LABEL: test_vmax_f64 + // LLVM-SAME: (<1 x double> [[a:%.*]], <1 x double> [[b:%.*]]) + // LLVM: [[TMP0:%.*]] = bitcast <1 x double> [[a]] to <8 x i8> + // LLVM: [[TMP1:%.*]] = bitcast <1 x double> [[b]] to <8 x i8> + // LLVM: [[VMAX2_I:%.*]] = call <1 x double> @llvm.maximum.v1f64(<1 x double> [[a]], <1 x double> [[b]]) + // LLVM: ret <1 x double> [[VMAX2_I]] +} // NYI-LABEL: @test_vmaxnm_f64( // NYI: [[TMP0:%.*]] = bitcast <1 x double> %a to <8 x i8> @@ -18872,19 +18967,29 @@ uint64x1_t test_vrsra_n_u64(uint64x1_t a, uint64x1_t b) { // return vmaxv_u32(a); // } -// NYI-LABEL: @test_vaddv_s32( -// NYI: [[VADDV_S32_I:%.*]] = call i32 @llvm.aarch64.neon.saddv.i32.v2i32(<2 x i32> %a) -// NYI: ret i32 [[VADDV_S32_I]] -// int32_t test_vaddv_s32(int32x2_t a) { -// return vaddv_s32(a); -// } +int32_t test_vaddv_s32(int32x2_t a) { + return vaddv_s32(a); -// NYI-LABEL: @test_vaddv_u32( -// NYI: [[VADDV_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uaddv.i32.v2i32(<2 x i32> %a) -// NYI: ret i32 [[VADDV_U32_I]] -// uint32_t test_vaddv_u32(uint32x2_t a) { -// return vaddv_u32(a); -// } + // CIR-LABEL: vaddv_s32 + // CIR: cir.llvm.intrinsic "aarch64.neon.saddv" {{%.*}} : (!cir.vector) -> !s32i + + // LLVM-LABEL: test_vaddv_s32 + // LLVM-SAME: (<2 x i32> [[a:%.*]]) + // LLVM: [[VADDV_S32_I:%.*]] = call i32 @llvm.aarch64.neon.saddv.i32.v2i32(<2 x i32> [[a]]) + // LLVM: ret i32 [[VADDV_S32_I]] +} + +uint32_t test_vaddv_u32(uint32x2_t a) { + return vaddv_u32(a); + + // CIR-LABEL: vaddv_u32 + // CIR: cir.llvm.intrinsic "aarch64.neon.uaddv" {{%.*}} : (!cir.vector) -> !u32i + + // LLVM-LABEL: test_vaddv_u32 + // LLVM-SAME: (<2 x i32> [[a:%.*]]) + // LLVM: [[VADDV_U32_I:%.*]] = call i32 @llvm.aarch64.neon.uaddv.i32.v2i32(<2 x i32> [[a]]) + // LLVM: ret i32 [[VADDV_U32_I]] +} // NYI-LABEL: @test_vaddlv_s32( // NYI: [[VADDLV_S32_I:%.*]] = call i64 @llvm.aarch64.neon.saddlv.i64.v2i32(<2 x i32> %a) diff --git a/clang/test/CIR/CodeGen/bitfields.c b/clang/test/CIR/CodeGen/bitfields.c index 9aace04ead08..5f13b424daa4 100644 --- a/clang/test/CIR/CodeGen/bitfields.c +++ b/clang/test/CIR/CodeGen/bitfields.c @@ -56,6 +56,7 @@ typedef struct { } U; // CHECK: !ty_D = !cir.struct +// CHECK: !ty_G = !cir.struct // CHECK: !ty_T = !cir.struct // CHECK: !ty_anon2E0_ = !cir.struct // CHECK: !ty_anon_struct = !cir.struct @@ -141,3 +142,20 @@ void createD() { int get_a(T *t) { return (t->a = 7); } + +typedef struct { + int x : 15; + int y ; +} G; + +// CHECK: cir.global external @g = #cir.const_struct<{#cir.int<133> : !u8i, #cir.int<127> : !u8i, #cir.int<254> : !s32i}> : !ty_anon_struct +G g = { -123, 254UL}; + +// CHECK: cir.func {{.*@get_y}} +// CHECK: %[[V1:.*]] = cir.get_global @g : !cir.ptr +// CHECK: %[[V2:.*]] = cir.cast(bitcast, %[[V1]] : !cir.ptr), !cir.ptr +// CHECK: %[[V3:.*]] = cir.get_member %[[V2]][1] {name = "y"} : !cir.ptr -> !cir.ptr +// CHECK: cir.load %[[V3]] : !cir.ptr, !s32i +int get_y() { + return g.y; +} diff --git a/clang/test/CIR/CodeGen/const-alloca.cpp b/clang/test/CIR/CodeGen/const-alloca.cpp index 9247b2692474..7cc9a5b57517 100644 --- a/clang/test/CIR/CodeGen/const-alloca.cpp +++ b/clang/test/CIR/CodeGen/const-alloca.cpp @@ -66,8 +66,8 @@ int local_const_load_store() { // LLVM-LABEL: @_Z22local_const_load_storev // LLVM: %[[#INIT:]] = call i32 @_Z11produce_intv() -// LLVM-NEXT: store i32 %[[#INIT]], ptr %[[#SLOT:]], align 4, !invariant.group !{{.+}} -// LLVM-NEXT: %{{.+}} = load i32, ptr %[[#SLOT]], align 4, !invariant.group !{{.+}} +// LLVM-NEXT: store i32 %[[#INIT]], ptr %[[#SLOT:]], align 4, !tbaa !{{.*}}, !invariant.group !{{.+}} +// LLVM-NEXT: %{{.+}} = load i32, ptr %[[#SLOT]], align 4, !tbaa !{{.*}}, !invariant.group !{{.+}} // LLVM: } int local_const_optimize() { @@ -80,7 +80,7 @@ int local_const_optimize() { // LLVM-LABEL: @_Z20local_const_optimizev() // LLVM-NEXT: %[[#slot:]] = alloca i32, align 4 // LLVM-NEXT: %[[#init:]] = tail call i32 @_Z11produce_intv() -// LLVM-NEXT: store i32 %[[#init]], ptr %[[#slot]], align 4, !invariant.group !{{.+}} +// LLVM-NEXT: store i32 %[[#init]], ptr %[[#slot]], align 4, !tbaa !{{.*}}, !invariant.group !{{.+}} // LLVM-NEXT: call void @_Z8blackboxRKi(ptr nonnull %[[#slot]]) // LLVM-NEXT: call void @_Z8blackboxRKi(ptr nonnull %[[#slot]]) // LLVM-NEXT: ret i32 %[[#init]] diff --git a/clang/test/CIR/CodeGen/tbaa-scalar.c b/clang/test/CIR/CodeGen/tbaa-scalar.c new file mode 100644 index 000000000000..b2f893b4f4ac --- /dev/null +++ b/clang/test/CIR/CodeGen/tbaa-scalar.c @@ -0,0 +1,148 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -O1 +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O1 +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O1 -relaxed-aliasing +// RUN: FileCheck --check-prefix=NO-TBAA --input-file=%t.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll -O0 +// RUN: FileCheck --check-prefix=NO-TBAA --input-file=%t.ll %s + +// NO-TBAA-NOT: !tbaa + +// CIR: #tbaa[[FLOAT_PTR:.*]] = #cir.tbaa_scalar> +// CIR: #tbaa[[FLOAT:.*]] = #cir.tbaa_scalar +// CIR: #tbaa[[DOUBLE_PTR:.*]] = #cir.tbaa_scalar> +// CIR: #tbaa[[DOUBLE:.*]] = #cir.tbaa_scalar +// CIR: #tbaa[[LONG_DOUBLE_PTR:.*]] = #cir.tbaa_scalar>> +// CIR: #tbaa[[LONG_DOUBLE:.*]] = #cir.tbaa_scalar> +// CIR: #tbaa[[INT:.*]] = #cir.tbaa_scalar +// CIR: #tbaa[[LONG:.*]] = #cir.tbaa_scalar +// CIR: #tbaa[[CHAR:.*]] = #cir.tbaa_scalar +// CIR: #tbaa[[INT_PTR:.*]] = #cir.tbaa_scalar> +// CIR: #tbaa[[LONG_PTR:.*]] = #cir.tbaa_scalar> +// CIR: #tbaa[[CHAR_PTR:.*]] = #cir.tbaa_scalar> + +void test_int_and_float(int *a, float *b) { + // CIR-LABEL: cir.func @test_int_and_float + // CIR: cir.scope + // CIR: %[[TMP1:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr tbaa(#tbaa[[INT_PTR]]) + // CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr, !s32i tbaa(#tbaa[[INT]]) + // CIR: cir.if + // CIR: %[[C2:.*]] = cir.const #cir.fp<2 + // CIR: %[[TMP3:.*]] = cir.load deref %[[ARG_b:.*]] : !cir.ptr>, !cir.ptr tbaa(#tbaa[[FLOAT_PTR]]) + // CIR: cir.store %[[C2]], %[[TMP3]] : !cir.float, !cir.ptr tbaa(#tbaa[[FLOAT]]) + // CIR: else + // CIR: %[[C3:.*]] = cir.const #cir.fp<3 + // CIR: %[[TMP4:.*]] = cir.load deref %[[ARG_b]] : !cir.ptr>, !cir.ptr tbaa(#tbaa[[FLOAT_PTR]]) + // CIR: cir.store %[[C3]], %[[TMP4]] : !cir.float, !cir.ptr tbaa(#tbaa[[FLOAT]]) + + // LLVM-LABEL: void @test_int_and_float + // LLVM: %[[ARG_a:.*]] = load i32, ptr %{{.*}}, align 4, !tbaa ![[TBAA_INT:.*]] + // LLVM: %[[COND:.*]] = icmp eq i32 %[[ARG_a]], 1 + // LLVM: %[[RET:.*]] = select i1 %[[COND]], float 2.000000e+00, float 3.000000e+00 + // LLVM: store float %[[RET]], ptr %{{.*}}, align 4, !tbaa ![[TBAA_FLOAT:.*]] + // LLVM: ret void + if (*a == 1) { + *b = 2.0f; + } else { + *b = 3.0f; + } +} + +void test_long_and_double(long *a, double *b) { + // CIR-LABEL: cir.func @test_long_and_double + // CIR: cir.scope + // CIR: %[[TMP1:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr tbaa(#tbaa[[LONG_PTR]]) + // CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr, !s64i tbaa(#tbaa[[LONG]]) + // CIR: cir.if + // CIR: %[[C2:.*]] = cir.const #cir.fp<2 + // CIR: %[[TMP3:.*]] = cir.load deref %[[ARG_b:.*]] : !cir.ptr>, !cir.ptr tbaa(#tbaa[[DOUBLE_PTR]]) + // CIR: cir.store %[[C2]], %[[TMP3]] : !cir.double, !cir.ptr tbaa(#tbaa[[DOUBLE]]) + // CIR: else + // CIR: %[[C3:.*]] = cir.const #cir.fp<3 + // CIR: %[[TMP4:.*]] = cir.load deref %[[ARG_b]] : !cir.ptr>, !cir.ptr tbaa(#tbaa[[DOUBLE_PTR]]) + // CIR: cir.store %[[C3]], %[[TMP4]] : !cir.double, !cir.ptr tbaa(#tbaa[[DOUBLE]]) + + // LLVM-LABEL: void @test_long_and_double + // LLVM: %[[ARG_a:.*]] = load i64, ptr %{{.*}}, align 8, !tbaa ![[TBAA_LONG:.*]] + // LLVM: %[[COND:.*]] = icmp eq i64 %[[ARG_a]], 1 + // LLVM: %[[RET:.*]] = select i1 %[[COND]], double 2.000000e+00, double 3.000000e+00 + // LLVM: store double %[[RET]], ptr %{{.*}}, align 8, !tbaa ![[TBAA_DOUBLE:.*]] + // LLVM: ret void + if (*a == 1L) { + *b = 2.0; + } else { + *b = 3.0; + } +} +void test_long_long_and_long_double(long long *a, long double *b) { + // CIR-LABEL: cir.func @test_long_long_and_long_double + // CIR: cir.scope + // CIR: %[[TMP1:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr tbaa(#tbaa[[LONG_PTR]]) + // CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr, !s64i tbaa(#tbaa[[LONG]]) + // CIR: cir.if + // CIR: %[[C2:.*]] = cir.const #cir.fp<2 + // CIR: %[[TMP3:.*]] = cir.load deref %[[ARG_b:.*]] : !cir.ptr>>, !cir.ptr> tbaa(#tbaa[[LONG_DOUBLE_PTR]]) + // CIR: cir.store %[[C2]], %[[TMP3]] : !cir.long_double, !cir.ptr> tbaa(#tbaa[[LONG_DOUBLE]]) + // CIR: else + // CIR: %[[C3:.*]] = cir.const #cir.fp<3 + // CIR: %[[TMP4:.*]] = cir.load deref %[[ARG_b]] : !cir.ptr>>, !cir.ptr> tbaa(#tbaa[[LONG_DOUBLE_PTR]]) + // CIR: cir.store %[[C3]], %[[TMP4]] : !cir.long_double, !cir.ptr> tbaa(#tbaa[[LONG_DOUBLE]]) + + // LLVM-LABEL: void @test_long_long_and_long_double + // LLVM: %[[ARG_a:.*]] = load i64, ptr %{{.*}}, align 8, !tbaa ![[TBAA_LONG_LONG:.*]] + // LLVM: %[[COND:.*]] = icmp eq i64 %[[ARG_a]], 1 + // LLVM: %[[RET:.*]] = select i1 %[[COND]], x86_fp80 0xK40008000000000000000, x86_fp80 0xK4000C000000000000000 + // LLVM: store x86_fp80 %[[RET]], ptr %{{.*}}, align 16, !tbaa ![[TBAA_LONG_DOUBLE:.*]] + // LLVM: ret void + if (*a == 1L) { + *b = 2.0L; + } else { + *b = 3.0L; + } +} + +void test_char(char *a, char* b) { + // CIR-LABEL: cir.func @test_char + // CIR: cir.scope + // CIR: %[[TMP1:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr tbaa(#tbaa[[CHAR_PTR]]) + // CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr, !s8i tbaa(#tbaa[[CHAR]]) + // CIR: cir.if + // CIR: %[[C2:.*]] = cir.const #cir.int<98> : !s32i + // CIR: %[[C2_CHAR:.*]] = cir.cast(integral, %[[C2]] : !s32i), !s8i + // CIR: %[[TMP3:.*]] = cir.load deref %[[ARG_b:.*]] : !cir.ptr>, !cir.ptr tbaa(#tbaa[[CHAR_PTR]]) + // CIR: cir.store %[[C2_CHAR]], %[[TMP3]] : !s8i, !cir.ptr tbaa(#tbaa[[CHAR]]) + // CIR: else + // CIR: %[[C3:.*]] = cir.const #cir.int<0> : !s32i + // CIR: %[[C3_CHAR:.*]] = cir.cast(integral, %[[C3]] : !s32i), !s8i + // CIR: %[[TMP4:.*]] = cir.load deref %[[ARG_b]] : !cir.ptr>, !cir.ptr tbaa(#tbaa[[CHAR_PTR]]) + // CIR: cir.store %[[C3_CHAR]], %[[TMP4]] : !s8i, !cir.ptr tbaa(#tbaa[[CHAR]]) + + + // LLVM-LABEL: void @test_char + // LLVM: %[[ARG_a:.*]] = load i8, ptr %{{.*}}, align 1, !tbaa ![[TBAA_CHAR:.*]] + // LLVM: %[[COND:.*]] = icmp eq i8 %[[ARG_a]], 97 + // LLVM: %[[RET:.*]] = select i1 %[[COND]], i8 98, i8 0 + // LLVM: store i8 %[[RET]], ptr %{{.*}}, align 1, !tbaa ![[TBAA_CHAR]] + // LLVM: ret void + if (*a == 'a') { + *b = 'b'; + } + else { + *b = '\0'; + } +} + +// LLVM: ![[TBAA_INT]] = !{![[TBAA_INT_PARENT:.*]], ![[TBAA_INT_PARENT]], i64 0} +// LLVM: ![[TBAA_INT_PARENT]] = !{!"int", ![[CHAR:.*]], i64 0} +// LLVM: ![[CHAR]] = !{!"omnipotent char", ![[ROOT:.*]], i64 0} +// LLVM: ![[ROOT]] = !{!"Simple C/C++ TBAA"} +// LLVM: ![[TBAA_FLOAT]] = !{![[TBAA_FLOAT_PARENT:.*]], ![[TBAA_FLOAT_PARENT]], i64 0} +// LLVM: ![[TBAA_FLOAT_PARENT]] = !{!"float", ![[CHAR]], i64 0} +// LLVM: ![[TBAA_LONG]] = !{![[TBAA_LONG_PARENT:.*]], ![[TBAA_LONG_PARENT]], i64 0} +// LLVM: ![[TBAA_LONG_PARENT]] = !{!"long", ![[CHAR]], i64 0} +// LLVM: ![[TBAA_DOUBLE]] = !{![[TBAA_DOUBLE_PARENT:.*]], ![[TBAA_DOUBLE_PARENT]], i64 0} +// LLVM: ![[TBAA_DOUBLE_PARENT]] = !{!"double", ![[CHAR]], i64 0} +// LLVM: ![[TBAA_LONG_DOUBLE]] = !{![[TBAA_LONG_DOUBLE_PARENT:.*]], ![[TBAA_LONG_DOUBLE_PARENT]], i64 0} +// LLVM: ![[TBAA_LONG_DOUBLE_PARENT]] = !{!"long double", ![[CHAR]], i64 0} +// LLVM: ![[TBAA_CHAR]] = !{![[CHAR]], ![[CHAR]], i64 0} diff --git a/clang/test/CIR/CodeGen/tbaa-struct.cpp b/clang/test/CIR/CodeGen/tbaa-struct.cpp new file mode 100644 index 000000000000..84c49df6b455 --- /dev/null +++ b/clang/test/CIR/CodeGen/tbaa-struct.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -O1 +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s + +// CIR: #tbaa[[tbaa_NYI:.*]] = #cir.tbaa +// CIR: #tbaa[[INT:.*]] = #cir.tbaa_scalar +// CIR: #tbaa[[INT_PTR:.*]] = #cir.tbaa_scalar> +// CIR: #tbaa[[StructA_PTR:.*]] = #cir.tbaa_scalar> + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +typedef struct +{ + uint16_t f16; + uint32_t f32; + uint16_t f16_2; + uint32_t f32_2; +} StructA; + +uint32_t g(uint32_t *s, StructA *A) { + // CIR-LABEL: cir.func @_Z1g + // CIR: %[[INT_1:.*]] = cir.const #cir.int<1> : !s32i + // CIR: %[[UINT_1:.*]] = cir.cast(integral, %[[INT_1]] : !s32i), !u32i + // CIR: cir.store %[[UINT_1]], %{{.*}} : !u32i, !cir.ptr tbaa(#tbaa[[INT]]) + // CIR: %[[INT_4:.*]] = cir.const #cir.int<4> : !s32i + // CIR: %[[UINT_4:.*]] = cir.cast(integral, %[[INT_4]] : !s32i), !u32i + // CIR: %[[pointer_to_StructA:.*]] = cir.load %{{.*}} : !cir.ptr>, !cir.ptr tbaa(#tbaa[[StructA_PTR]]) + // CIR: %[[A_f32:.*]] = cir.get_member %[[pointer_to_StructA]][1] {name = "f32"} : !cir.ptr -> !cir.ptr + // CIR: cir.store %[[UINT_4]], %[[A_f32]] : !u32i, !cir.ptr tbaa(#tbaa[[tbaa_NYI]]) + + *s = 1; + A->f32 = 4; + return *s; +} diff --git a/clang/test/CIR/CodeGen/tbaa-vptr.cpp b/clang/test/CIR/CodeGen/tbaa-vptr.cpp new file mode 100644 index 000000000000..dbe28be626a2 --- /dev/null +++ b/clang/test/CIR/CodeGen/tbaa-vptr.cpp @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -O1 +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s + +// CIR-NOT: #tbaa + +struct Member { + ~Member(); +}; + +struct A { + virtual ~A(); +}; + +struct B : A { + Member m; + virtual ~B(); +}; +B::~B() { } diff --git a/clang/test/CIR/CodeGen/tbaa.c b/clang/test/CIR/CodeGen/tbaa.c deleted file mode 100644 index 43cdde47ecb7..000000000000 --- a/clang/test/CIR/CodeGen/tbaa.c +++ /dev/null @@ -1,22 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -O1 -// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s - -// CIR: #tbaa[[TBAA_NO:.*]] = #cir.tbaa -void f(int *a, float *b) { - // CIR: cir.scope - // CIR: %[[TMP1:.*]] = cir.load deref %{{.*}} : !cir.ptr>, !cir.ptr tbaa([#tbaa[[TBAA_NO]]]) - // CIR: %[[TMP2:.*]] = cir.load %[[TMP1]] : !cir.ptr, !s32i tbaa([#tbaa[[TBAA_NO]]]) - // CIR: cir.if - // CIR: %[[C2:.*]] = cir.const #cir.fp<2 - // CIR: %[[TMP3:.*]] = cir.load deref %[[ARG_b:.*]] : !cir.ptr>, !cir.ptr tbaa([#tbaa[[TBAA_NO]]]) - // CIR: cir.store %[[C2]], %[[TMP3]] : !cir.float, !cir.ptr tbaa([#tbaa[[TBAA_NO]]]) - // CIR: else - // CIR: %[[C3:.*]] = cir.const #cir.fp<3 - // CIR: %[[TMP4:.*]] = cir.load deref %[[ARG_b]] : !cir.ptr>, !cir.ptr tbaa([#tbaa[[TBAA_NO]]]) - // CIR: cir.store %[[C3]], %[[TMP4]] : !cir.float, !cir.ptr tbaa([#tbaa[[TBAA_NO]]]) - if (*a == 1) { - *b = 2.0f; - } else { - *b = 3.0f; - } -} diff --git a/clang/test/CIR/crashes/copy-on-catch.cpp b/clang/test/CIR/crashes/copy-on-catch.cpp new file mode 100644 index 000000000000..9bf11f7a2408 --- /dev/null +++ b/clang/test/CIR/crashes/copy-on-catch.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -triple aarch64-none-linux-android21 -fclangir -emit-cir %s -o %t.cir -fcxx-exceptions -fexceptions | FileCheck %s +// XFAIL: * + +// CHECK: cir.func + +struct E {}; +E e; + +void throws() { throw e; } + +void bar() { + try { + throws(); + } catch (E e) { + } +} diff --git a/clang/utils/TableGen/CIRLoweringEmitter.cpp b/clang/utils/TableGen/CIRLoweringEmitter.cpp index 9b71e9ab597d..11abf5a7ec71 100644 --- a/clang/utils/TableGen/CIRLoweringEmitter.cpp +++ b/clang/utils/TableGen/CIRLoweringEmitter.cpp @@ -16,6 +16,10 @@ std::string ClassDeclaration; std::string ClassDefinitions; std::string ClassList; +std::string TBAANameFunctionDeclaration; +std::string TBAANameFunctionDefinitions; +std::string TBAANameClassList; + void GenerateLowering(const Record *Operation) { using namespace std::string_literals; std::string Name = Operation->getName().str(); @@ -68,6 +72,24 @@ CIR)C++" + ClassList += ", CIR" + Name + "Lowering\n"; } + +void GenerateTBAANameLowering(const Record *def) { + using namespace std::string_literals; + std::string Name = def->getValueAsString("cppClassName").str(); + std::string TBAAName = def->getValueAsString("tbaaName").str(); + TBAANameFunctionDeclaration += "llvm::StringRef getTBAAName(cir::"; + TBAANameFunctionDeclaration += Name + " ty);"; + TBAANameFunctionDeclaration += "\n"; + TBAANameFunctionDefinitions += "llvm::StringRef getTBAAName(cir::"; + TBAANameFunctionDefinitions += Name + " ty) {"; + TBAANameFunctionDefinitions += " return \"" + TBAAName + "\";"; + TBAANameFunctionDefinitions += "}"; + TBAANameFunctionDefinitions += "\n"; + TBAANameClassList += "\n"; + TBAANameClassList += "cir::"; + TBAANameClassList += Name; + TBAANameClassList += ", "; +} } // namespace void clang::EmitCIRBuiltinsLowering(const RecordKeeper &Records, @@ -85,3 +107,25 @@ void clang::EmitCIRBuiltinsLowering(const RecordKeeper &Records, << ClassDefinitions << "\n#endif\n"; OS << "#ifdef GET_BUILTIN_LOWERING_LIST\n" << ClassList << "\n#endif\n"; } + +void clang::EmitCIRTBAANameLowering(const RecordKeeper &Records, + raw_ostream &OS) { + emitSourceFileHeader("Lowering of ClangIR TBAA Name", OS); + + for (const auto *Builtin : + Records.getAllDerivedDefinitions("TBAALoweringInfo")) { + if (!Builtin->getValueAsString("tbaaName").empty()) + GenerateTBAANameLowering(Builtin); + } + + OS << "#ifdef GET_TBAANAME_LOWERING_FUNCTIONS_DECLARE\n" + << TBAANameFunctionDeclaration << "\n#endif\n"; + OS << "#ifdef GET_TBAANAME_LOWERING_FUNCTIONS_DEF\n" + << TBAANameFunctionDefinitions << "\n#endif\n"; + // remove last `, ` + if (!TBAANameClassList.empty()) { + TBAANameClassList.resize(TBAANameClassList.size() - 2); + } + OS << "#ifdef GET_TBAANAME_LOWERING_LIST\n" + << TBAANameClassList << "\n#endif\n"; +} diff --git a/clang/utils/TableGen/TableGen.cpp b/clang/utils/TableGen/TableGen.cpp index c9a0be40a90a..2d8b1397b980 100644 --- a/clang/utils/TableGen/TableGen.cpp +++ b/clang/utils/TableGen/TableGen.cpp @@ -26,6 +26,7 @@ enum ActionType { PrintRecords, DumpJSON, GenCIRBuiltinsLowering, + GenCIRTBAANameLowering, GenClangAttrClasses, GenClangAttrParserStringSwitches, GenClangAttrSubjectMatchRulesParserStringSwitches, @@ -123,6 +124,8 @@ cl::opt Action( clEnumValN(GenCIRBuiltinsLowering, "gen-cir-builtins-lowering", "Generate lowering of ClangIR builtins to equivalent LLVM " "IR builtins"), + clEnumValN(GenCIRTBAANameLowering, "gen-cir-tbaa-name-lowering", + "Generate lowering of ClangIR TBAA Name"), clEnumValN(GenClangAttrClasses, "gen-clang-attr-classes", "Generate clang attribute clases"), clEnumValN(GenClangAttrParserStringSwitches, @@ -331,6 +334,9 @@ bool ClangTableGenMain(raw_ostream &OS, const RecordKeeper &Records) { case GenCIRBuiltinsLowering: EmitCIRBuiltinsLowering(Records, OS); break; + case GenCIRTBAANameLowering: + EmitCIRTBAANameLowering(Records, OS); + break; case GenClangAttrClasses: EmitClangAttrClass(Records, OS); break; diff --git a/clang/utils/TableGen/TableGenBackends.h b/clang/utils/TableGen/TableGenBackends.h index 972357bac4d8..c3eb7b432bb2 100644 --- a/clang/utils/TableGen/TableGenBackends.h +++ b/clang/utils/TableGen/TableGenBackends.h @@ -26,6 +26,8 @@ namespace clang { void EmitCIRBuiltinsLowering(const llvm::RecordKeeper &RK, llvm::raw_ostream &OS); +void EmitCIRTBAANameLowering(const llvm::RecordKeeper &RK, + llvm::raw_ostream &OS); void EmitClangDeclContext(const llvm::RecordKeeper &RK, llvm::raw_ostream &OS); /** @param PriorizeIfSubclassOf These classes should be prioritized in the output.