25#define GEN_PASS_DEF_ARITHTOLLVMCONVERSIONPASS
26#include "mlir/Conversion/Passes.h.inc"
46template <
typename SourceOp,
typename TargetOp,
bool HasRoundingMode,
47 template <
typename,
typename>
typename AttrConvert =
49 bool FailOnUnsupportedFP =
false>
50struct ConstrainedVectorConvertToLLVMPattern
52 FailOnUnsupportedFP> {
53 using VectorConvertToLLVMPattern<
54 SourceOp, TargetOp, AttrConvert,
55 FailOnUnsupportedFP>::VectorConvertToLLVMPattern;
58 matchAndRewrite(SourceOp op,
typename SourceOp::Adaptor adaptor,
59 ConversionPatternRewriter &rewriter)
const override {
60 if (HasRoundingMode !=
static_cast<bool>(op.getRoundingModeAttr()))
62 return VectorConvertToLLVMPattern<
63 SourceOp, TargetOp, AttrConvert,
64 FailOnUnsupportedFP>::matchAndRewrite(op, adaptor, rewriter);
70struct IdentityBitcastLowering final
71 :
public OpConversionPattern<arith::BitcastOp> {
75 matchAndRewrite(arith::BitcastOp op, OpAdaptor adaptor,
76 ConversionPatternRewriter &rewriter)
const final {
77 Value src = adaptor.getIn();
78 Type resultType = getTypeConverter()->convertType(op.getType());
79 if (src.
getType() != resultType)
80 return rewriter.notifyMatchFailure(op,
"Types are different");
82 rewriter.replaceOp(op, src);
92 ConstrainedVectorConvertToLLVMPattern<arith::AddFOp, LLVM::FAddOp,
96using ConstrainedAddFOpLowering = ConstrainedVectorConvertToLLVMPattern<
97 arith::AddFOp, LLVM::ConstrainedFAddIntr,
true,
103using BitcastOpLowering =
105using DivFOpLowering =
106 ConstrainedVectorConvertToLLVMPattern<arith::DivFOp, LLVM::FDivOp,
110using ConstrainedDivFOpLowering = ConstrainedVectorConvertToLLVMPattern<
111 arith::DivFOp, LLVM::ConstrainedFDivIntr,
true,
113using DivSIOpLowering =
115using DivUIOpLowering =
117using ExtFOpLowering =
121using ExtSIOpLowering =
123using ExtUIOpLowering =
126using FPToSIOpLowering =
130using FPToUIOpLowering =
134using MaximumFOpLowering =
138using MaxNumFOpLowering =
142using MaxSIOpLowering =
144using MaxUIOpLowering =
146using MinimumFOpLowering =
150using MinNumFOpLowering =
154using MinSIOpLowering =
156using MinUIOpLowering =
158using MulFOpLowering =
159 ConstrainedVectorConvertToLLVMPattern<arith::MulFOp, LLVM::FMulOp,
163using ConstrainedMulFOpLowering = ConstrainedVectorConvertToLLVMPattern<
164 arith::MulFOp, LLVM::ConstrainedFMulIntr,
true,
166using MulIOpLowering =
169using NegFOpLowering =
174using RemFOpLowering =
178using RemSIOpLowering =
180using RemUIOpLowering =
182using SelectOpLowering =
184using ShLIOpLowering =
187using ShRSIOpLowering =
189using ShRUIOpLowering =
191using SIToFPOpLowering =
193using SubFOpLowering =
194 ConstrainedVectorConvertToLLVMPattern<arith::SubFOp, LLVM::FSubOp,
198using ConstrainedSubFOpLowering = ConstrainedVectorConvertToLLVMPattern<
199 arith::SubFOp, LLVM::ConstrainedFSubIntr,
true,
201using SubIOpLowering =
204using TruncFOpLowering =
205 ConstrainedVectorConvertToLLVMPattern<arith::TruncFOp, LLVM::FPTruncOp,
209using ConstrainedTruncFOpLowering = ConstrainedVectorConvertToLLVMPattern<
210 arith::TruncFOp, LLVM::ConstrainedFPTruncIntr,
true,
212using TruncIOpLowering =
215using UIToFPOpLowering =
230 matchAndRewrite(arith::ConstantOp op, OpAdaptor adaptor,
231 ConversionPatternRewriter &rewriter)
const override;
238template <
typename OpTy,
typename ExtCastTy>
240 using ConvertOpToLLVMPattern<OpTy>::ConvertOpToLLVMPattern;
243 matchAndRewrite(OpTy op,
typename OpTy::Adaptor adaptor,
244 ConversionPatternRewriter &rewriter)
const override;
247using IndexCastOpSILowering =
248 IndexCastOpLowering<arith::IndexCastOp, LLVM::SExtOp>;
249using IndexCastOpUILowering =
250 IndexCastOpLowering<arith::IndexCastUIOp, LLVM::ZExtOp>;
252struct AddUIExtendedOpLowering
257 matchAndRewrite(arith::AddUIExtendedOp op, OpAdaptor adaptor,
258 ConversionPatternRewriter &rewriter)
const override;
261struct SubUIExtendedOpLowering
266 matchAndRewrite(arith::SubUIExtendedOp op, OpAdaptor adaptor,
267 ConversionPatternRewriter &rewriter)
const override;
270template <
typename ArithMulOp,
bool IsSigned>
272 using ConvertOpToLLVMPattern<ArithMulOp>::ConvertOpToLLVMPattern;
275 matchAndRewrite(ArithMulOp op,
typename ArithMulOp::Adaptor adaptor,
276 ConversionPatternRewriter &rewriter)
const override;
279using MulSIExtendedOpLowering =
280 MulIExtendedOpLowering<arith::MulSIExtendedOp, true>;
281using MulUIExtendedOpLowering =
282 MulIExtendedOpLowering<arith::MulUIExtendedOp, false>;
288 matchAndRewrite(arith::CmpIOp op, OpAdaptor adaptor,
289 ConversionPatternRewriter &rewriter)
const override;
296 matchAndRewrite(arith::CmpFOp op, OpAdaptor adaptor,
297 ConversionPatternRewriter &rewriter)
const override;
309 matchAndRewrite(arith::ConvertFOp op, OpAdaptor adaptor,
310 ConversionPatternRewriter &rewriter)
const override {
312 *getTypeConverter()))
313 return rewriter.notifyMatchFailure(op,
"unsupported floating point type");
319 assert(((srcType.isBF16() && dstType.isF16()) ||
320 (srcType.isF16() && dstType.isBF16())) &&
321 "only bf16 <-> f16 conversions are supported");
323 Type convertedType = getTypeConverter()->convertType(op.getType());
325 return rewriter.notifyMatchFailure(op,
"failed to convert result type");
327 Value input = adaptor.getIn();
328 Location loc = op.getLoc();
330 if (!isa<LLVM::LLVMArrayType>(input.
getType())) {
331 rewriter.replaceOp(op,
332 emitConversion(rewriter, loc, input, convertedType));
336 if (!isa<VectorType>(op.getType()))
337 return rewriter.notifyMatchFailure(op,
"expected vector result type");
340 op.getOperation(), adaptor.getOperands(), *getTypeConverter(),
341 [&](Type llvm1DVectorTy,
ValueRange operands) -> Value {
342 return emitConversion(rewriter, loc, operands.front(),
349 static Value emitConversion(ConversionPatternRewriter &rewriter, Location loc,
350 Value input, Type targetType) {
351 Type f32Scalar = Float32Type::get(rewriter.getContext());
352 Type f32Ty = f32Scalar;
353 if (
auto vecTy = dyn_cast<VectorType>(targetType))
354 f32Ty = VectorType::get(vecTy.getShape(), f32Scalar);
356 Value ext = LLVM::FPExtOp::create(rewriter, loc, f32Ty, input);
357 return LLVM::FPTruncOp::create(rewriter, loc, targetType, ext);
366 matchAndRewrite(arith::SelectOp op, Adaptor adaptor,
367 ConversionPatternRewriter &rewriter)
const override;
389 if (sourceElementType == targetElementType)
392 auto targetIntType = dyn_cast<IntegerType>(targetElementType);
399 if (
auto sourceFloatType = dyn_cast<FloatType>(sourceElementType)) {
400 if (sourceFloatType.getWidth() != targetIntType.getWidth())
409 if (!isa<IndexType>(sourceElementType))
413 unsigned width = targetIntType.getWidth();
415 if (
auto intAttr = dyn_cast<IntegerAttr>(attr))
416 return IntegerAttr::get(targetIntType,
417 intAttr.getValue().sextOrTrunc(width));
420 return values.mapValues(targetIntType, [&](
const APInt &value) {
421 return value.sextOrTrunc(width);
425 if (
auto denseAttr = dyn_cast<DenseIntElementsAttr>(attr))
426 return retypeValues(denseAttr);
428 if (
auto sparseAttr = dyn_cast<SparseElementsAttr>(attr))
429 return SparseElementsAttr::get(
430 cast<ShapedType>(attr.getType()).clone(targetIntType),
431 sparseAttr.getIndices(),
432 retypeValues(cast<DenseIntElementsAttr>(sparseAttr.getValues())));
438 if (
auto resourceAttr = dyn_cast<DenseResourceElementsAttr>(attr)) {
439 if (width != IndexType::kInternalStorageBitWidth)
441 return DenseResourceElementsAttr::get(
442 cast<ShapedType>(attr.getType()).clone(targetIntType),
443 resourceAttr.getRawHandle());
450ConstantOpLowering::matchAndRewrite(arith::ConstantOp op, OpAdaptor adaptor,
451 ConversionPatternRewriter &rewriter)
const {
452 Type resultType = getTypeConverter()->convertType(op.getType());
454 return rewriter.notifyMatchFailure(op,
"failed to convert result type");
458 return rewriter.notifyMatchFailure(
459 op,
"failed to convert value attribute to the converted result type");
464 DictionaryAttr discardableAttrs = op->getDiscardableAttrDictionary();
466 LLVM::ConstantOp::create(rewriter, op.getLoc(), resultType, value);
467 constantOp->setDiscardableAttrs(discardableAttrs);
468 rewriter.replaceOp(op, constantOp);
476template <
typename OpTy,
typename ExtCastTy>
477LogicalResult IndexCastOpLowering<OpTy, ExtCastTy>::matchAndRewrite(
478 OpTy op,
typename OpTy::Adaptor adaptor,
479 ConversionPatternRewriter &rewriter)
const {
480 Type resultType = op.getResult().getType();
481 Type targetElementType =
483 Type sourceElementType =
488 if (targetBits == sourceBits) {
489 rewriter.replaceOp(op, adaptor.getIn());
496 if (isa<MemRefType>(op.getIn().getType())) {
497 rewriter.replaceOp(op, adaptor.getIn());
501 bool isNonNeg =
false;
502 if constexpr (std::is_same_v<ExtCastTy, LLVM::ZExtOp>)
503 isNonNeg = op.getNonNeg();
506 Type operandType = adaptor.getIn().getType();
507 if (!isa<LLVM::LLVMArrayType>(operandType)) {
508 Type targetType = this->typeConverter->convertType(resultType);
509 if (targetBits < sourceBits) {
510 rewriter.replaceOpWithNewOp<LLVM::TruncOp>(op, targetType,
513 auto extOp = rewriter.replaceOpWithNewOp<ExtCastTy>(op, targetType,
515 if constexpr (std::is_same_v<ExtCastTy, LLVM::ZExtOp>)
516 extOp.setNonNeg(isNonNeg);
521 if (!isa<VectorType>(resultType))
522 return rewriter.notifyMatchFailure(op,
"expected vector result type");
525 op.getOperation(), adaptor.getOperands(), *(this->getTypeConverter()),
526 [&](Type llvm1DVectorTy,
ValueRange operands) -> Value {
527 typename OpTy::Adaptor adaptor(operands);
528 if (targetBits < sourceBits) {
529 return LLVM::TruncOp::create(rewriter, op.getLoc(), llvm1DVectorTy,
532 auto extOp = ExtCastTy::create(rewriter, op.getLoc(), llvm1DVectorTy,
534 if constexpr (std::is_same_v<ExtCastTy, LLVM::ZExtOp>) {
536 extOp.setNonNeg(
true);
547LogicalResult AddUIExtendedOpLowering::matchAndRewrite(
548 arith::AddUIExtendedOp op, OpAdaptor adaptor,
549 ConversionPatternRewriter &rewriter)
const {
550 Type operandType = adaptor.getLhs().getType();
551 Type sumResultType = op.getSum().getType();
552 Type overflowResultType = op.getOverflow().getType();
554 if (!LLVM::isCompatibleType(operandType))
557 MLIRContext *ctx = rewriter.getContext();
558 Location loc = op.getLoc();
561 if (!isa<LLVM::LLVMArrayType>(operandType)) {
562 Type newOverflowType = typeConverter->convertType(overflowResultType);
564 LLVM::LLVMStructType::getLiteral(ctx, {sumResultType, newOverflowType});
565 Value addOverflow = LLVM::UAddWithOverflowOp::create(
566 rewriter, loc, structType, adaptor.getLhs(), adaptor.getRhs());
568 LLVM::ExtractValueOp::create(rewriter, loc, addOverflow, 0);
569 Value overflowExtracted =
570 LLVM::ExtractValueOp::create(rewriter, loc, addOverflow, 1);
571 rewriter.replaceOp(op, {sumExtracted, overflowExtracted});
575 if (!isa<VectorType>(sumResultType))
576 return rewriter.notifyMatchFailure(loc,
"expected vector result types");
578 return rewriter.notifyMatchFailure(loc,
579 "ND vector types are not supported yet");
586LogicalResult SubUIExtendedOpLowering::matchAndRewrite(
587 arith::SubUIExtendedOp op, OpAdaptor adaptor,
588 ConversionPatternRewriter &rewriter)
const {
589 Type operandType = adaptor.getLhs().getType();
590 Type diffResultType = op.getDiff().getType();
591 Type borrowResultType = op.getBorrow().getType();
593 if (!LLVM::isCompatibleType(operandType))
596 MLIRContext *ctx = rewriter.getContext();
597 Location loc = op.getLoc();
600 if (!isa<LLVM::LLVMArrayType>(operandType)) {
601 Type newBorrowType = typeConverter->convertType(borrowResultType);
603 LLVM::LLVMStructType::getLiteral(ctx, {diffResultType, newBorrowType});
604 Value subOverflow = LLVM::USubWithOverflowOp::create(
605 rewriter, loc, structType, adaptor.getLhs(), adaptor.getRhs());
606 Value diffExtracted =
607 LLVM::ExtractValueOp::create(rewriter, loc, subOverflow, 0);
608 Value borrowExtracted =
609 LLVM::ExtractValueOp::create(rewriter, loc, subOverflow, 1);
610 rewriter.replaceOp(op, {diffExtracted, borrowExtracted});
614 if (!isa<VectorType>(diffResultType))
615 return rewriter.notifyMatchFailure(loc,
"expected vector result types");
617 return rewriter.notifyMatchFailure(loc,
618 "ND vector types are not supported yet");
625template <
typename ArithMulOp,
bool IsSigned>
626LogicalResult MulIExtendedOpLowering<ArithMulOp, IsSigned>::matchAndRewrite(
627 ArithMulOp op,
typename ArithMulOp::Adaptor adaptor,
628 ConversionPatternRewriter &rewriter)
const {
629 Type resultType = adaptor.getLhs().getType();
631 if (!LLVM::isCompatibleType(resultType))
634 Location loc = op.getLoc();
640 if (!isa<LLVM::LLVMArrayType>(resultType)) {
642 TypedAttr shiftValAttr;
644 if (
auto intTy = dyn_cast<IntegerType>(resultType)) {
645 unsigned resultBitwidth = intTy.getWidth();
646 auto attrTy = rewriter.getIntegerType(resultBitwidth * 2);
647 shiftValAttr = rewriter.getIntegerAttr(attrTy, resultBitwidth);
649 auto vecTy = cast<VectorType>(resultType);
650 unsigned resultBitwidth = vecTy.getElementTypeBitWidth();
651 auto attrTy = VectorType::get(
652 vecTy.getShape(), rewriter.getIntegerType(resultBitwidth * 2));
653 shiftValAttr = SplatElementsAttr::get(
654 attrTy, APInt(resultBitwidth * 2, resultBitwidth));
656 Type wideType = shiftValAttr.getType();
657 assert(LLVM::isCompatibleType(wideType) &&
658 "LLVM dialect should support all signless integer types");
660 using LLVMExtOp = std::conditional_t<IsSigned, LLVM::SExtOp, LLVM::ZExtOp>;
661 Value lhsExt = LLVMExtOp::create(rewriter, loc, wideType, adaptor.getLhs());
662 Value rhsExt = LLVMExtOp::create(rewriter, loc, wideType, adaptor.getRhs());
663 Value mulExt = LLVM::MulOp::create(rewriter, loc, wideType, lhsExt, rhsExt);
666 Value low = LLVM::TruncOp::create(rewriter, loc, resultType, mulExt);
667 Value shiftVal = LLVM::ConstantOp::create(rewriter, loc, shiftValAttr);
668 Value highExt = LLVM::LShrOp::create(rewriter, loc, mulExt, shiftVal);
669 Value high = LLVM::TruncOp::create(rewriter, loc, resultType, highExt);
671 rewriter.replaceOp(op, {low, high});
675 if (!isa<VectorType>(resultType))
676 return rewriter.notifyMatchFailure(op,
"expected vector result type");
678 return rewriter.notifyMatchFailure(op,
679 "ND vector types are not supported yet");
688template <
typename LLVMPredType,
typename PredType>
690 return static_cast<LLVMPredType
>(pred);
694CmpIOpLowering::matchAndRewrite(arith::CmpIOp op, OpAdaptor adaptor,
695 ConversionPatternRewriter &rewriter)
const {
696 Type operandType = adaptor.getLhs().getType();
697 Type resultType = op.getResult().getType();
700 if (!isa<LLVM::LLVMArrayType>(operandType)) {
701 rewriter.replaceOpWithNewOp<LLVM::ICmpOp>(
702 op, typeConverter->convertType(resultType),
704 adaptor.getLhs(), adaptor.getRhs());
708 if (!isa<VectorType>(resultType))
709 return rewriter.notifyMatchFailure(op,
"expected vector result type");
712 op.getOperation(), adaptor.getOperands(), *getTypeConverter(),
713 [&](Type llvm1DVectorTy,
ValueRange operands) {
714 OpAdaptor adaptor(operands);
715 return LLVM::ICmpOp::create(
716 rewriter, op.getLoc(), llvm1DVectorTy,
718 adaptor.getLhs(), adaptor.getRhs());
728CmpFOpLowering::matchAndRewrite(arith::CmpFOp op, OpAdaptor adaptor,
729 ConversionPatternRewriter &rewriter)
const {
731 op.getLhs().getType()))
732 return rewriter.notifyMatchFailure(op,
"unsupported floating point type");
734 Type operandType = adaptor.getLhs().getType();
735 Type resultType = op.getResult().getType();
736 LLVM::FastmathFlags fmf =
737 arith::convertArithFastMathFlagsToLLVM(op.getFastmath());
740 if (!isa<LLVM::LLVMArrayType>(operandType)) {
741 rewriter.replaceOpWithNewOp<LLVM::FCmpOp>(
742 op, typeConverter->convertType(resultType),
744 adaptor.getLhs(), adaptor.getRhs(), fmf);
748 if (!isa<VectorType>(resultType))
749 return rewriter.notifyMatchFailure(op,
"expected vector result type");
752 op.getOperation(), adaptor.getOperands(), *getTypeConverter(),
753 [&](Type llvm1DVectorTy,
ValueRange operands) {
754 OpAdaptor adaptor(operands);
755 return LLVM::FCmpOp::create(
756 rewriter, op.getLoc(), llvm1DVectorTy,
758 adaptor.getLhs(), adaptor.getRhs(), fmf);
770LogicalResult SelectOpOneToNLowering::matchAndRewrite(
771 arith::SelectOp op, Adaptor adaptor,
772 ConversionPatternRewriter &rewriter)
const {
774 if (llvm::hasSingleElement(adaptor.getTrueValue()))
775 return rewriter.notifyMatchFailure(
776 op,
"not a 1:N conversion, 1:1 pattern will match");
777 if (!op.getCondition().getType().isInteger(1))
778 return rewriter.notifyMatchFailure(op,
779 "non-i1 conditions are not supported");
780 SmallVector<Value> results;
781 for (
auto [trueValue, falseValue] :
782 llvm::zip_equal(adaptor.getTrueValue(), adaptor.getFalseValue()))
783 results.push_back(arith::SelectOp::create(
784 rewriter, op.getLoc(), op.getCondition(), trueValue, falseValue));
785 rewriter.replaceOpWithMultiple(op, {results});
794struct ArithToLLVMConversionPass
795 :
public impl::ArithToLLVMConversionPassBase<ArithToLLVMConversionPass> {
798 void runOnOperation()
override {
804 options.overrideIndexBitwidth(indexBitwidth);
807 arith::populateCeilFloorDivExpandOpsPatterns(patterns);
808 arith::populateArithToLLVMConversionPatterns(converter, patterns);
810 if (
failed(applyPartialConversion(getOperation(),
target,
811 std::move(patterns))))
823struct ArithToLLVMDialectInterface :
public ConvertToLLVMPatternInterface {
824 ArithToLLVMDialectInterface(Dialect *dialect)
825 : ConvertToLLVMPatternInterface(dialect) {}
827 void loadDependentDialects(MLIRContext *context)
const final {
828 context->loadDialect<LLVM::LLVMDialect>();
833 void populateConvertToLLVMConversionPatterns(
834 ConversionTarget &
target, LLVMTypeConverter &typeConverter,
835 RewritePatternSet &patterns)
const final {
836 arith::populateCeilFloorDivExpandOpsPatterns(patterns);
837 arith::populateArithToLLVMConversionPatterns(typeConverter, patterns);
845 dialect->addInterfaces<ArithToLLVMDialectInterface>();
858 patterns.
add<IdentityBitcastLowering>(converter, patterns.
getContext(),
864 ConstrainedAddFOpLowering,
867 AddUIExtendedOpLowering,
868 SubUIExtendedOpLowering,
874 ConstrainedDivFOpLowering,
883 IndexCastOpSILowering,
884 IndexCastOpUILowering,
894 ConstrainedMulFOpLowering,
896 MulSIExtendedOpLowering,
897 MulUIExtendedOpLowering,
904 SelectOpOneToNLowering,
910 ConstrainedSubFOpLowering,
913 ConstrainedTruncFOpLowering,
static LLVMPredType convertCmpPredicate(PredType pred)
static TypedAttr convertConstantValue(TypedAttr attr, Type resultType)
Retypes attr for a llvm.mlir.constant of resultType.
static llvm::ManagedStatic< PassManagerOptions > options
Utility class for operation conversions targeting the LLVM dialect that match exactly one source oper...
ConvertOpToLLVMPattern(const LLVMTypeConverter &typeConverter, PatternBenefit benefit=1)
typename SourceOp::template GenericAdaptor< ArrayRef< ValueRange > > OneToNOpAdaptor
An attribute that represents a reference to a dense integer vector or tensor object.
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
Conversion from types to the LLVM IR dialect.
MLIRContext is the top-level object for a collection of MLIR operations.
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Type getType() const
Return the type of this value.
Basic lowering implementation to rewrite Ops with just one result to the LLVM Dialect.
LogicalResult handleMultidimensionalVectors(Operation *op, ValueRange operands, const LLVMTypeConverter &typeConverter, std::function< Value(Type, ValueRange)> createOperand, ConversionPatternRewriter &rewriter)
bool isUnsupportedFloatingPointType(const TypeConverter &typeConverter, Type type)
Return "true" if the given type is an unsupported floating point type.
bool opHasUnsupportedFloatingPointTypes(Operation *op, const TypeConverter &typeConverter)
Return "true" if the given op has any unsupported floating point types (either operands or results).
Type getConstantElementType(Type type)
Determines the element type of type the way the llvm.mlir.constant verifier does, i....
void populateArithToLLVMConversionPatterns(const LLVMTypeConverter &converter, RewritePatternSet &patterns)
void registerConvertArithToLLVMInterface(DialectRegistry ®istry)
Include the generated interface declarations.
static constexpr unsigned kDeriveIndexBitwidthFromDataLayout
Value to pass as bitwidth for the index type when the converter is expected to derive the bitwidth fr...
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.