void PTXInstPrinter::printOperand(const MCInst *MI, unsigned OpNo, raw_ostream &O) { const MCOperand &Op = MI->getOperand(OpNo); if (Op.isImm()) { O << Op.getImm(); } else if (Op.isFPImm()) { double Imm = Op.getFPImm(); APFloat FPImm(Imm); APInt FPIntImm = FPImm.bitcastToAPInt(); O << "0D"; // PTX requires us to output the full 64 bits, even if the number is zero if (FPIntImm.getZExtValue() > 0) { O << FPIntImm.toString(16, false); } else { O << "0000000000000000"; } } else if (Op.isReg()) { printRegName(O, Op.getReg()); } else { assert(Op.isExpr() && "unknown operand kind in printOperand"); const MCExpr *Expr = Op.getExpr(); if (const MCSymbolRefExpr *SymRefExpr = dyn_cast<MCSymbolRefExpr>(Expr)) { const MCSymbol &Sym = SymRefExpr->getSymbol(); O << Sym.getName(); } else { O << *Op.getExpr(); } } }
std::string get_string(const APInt &api) { std::ostringstream str; for (unsigned count = api.countLeadingZeros(); count > 0; count--) str << "0"; if (api != 0) str << api.toString(2, false /* treat as unsigned */); return str.str(); }
static SILInstruction *constantFoldBuiltin(BuiltinInst *BI, Optional<bool> &ResultsInError) { const IntrinsicInfo &Intrinsic = BI->getIntrinsicInfo(); SILModule &M = BI->getModule(); // If it's an llvm intrinsic, fold the intrinsic. if (Intrinsic.ID != llvm::Intrinsic::not_intrinsic) return constantFoldIntrinsic(BI, Intrinsic.ID, ResultsInError); // Otherwise, it should be one of the builtin functions. OperandValueArrayRef Args = BI->getArguments(); const BuiltinInfo &Builtin = BI->getBuiltinInfo(); switch (Builtin.ID) { default: break; // Check and fold binary arithmetic with overflow. #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(id, name, _, attrs, overload) \ case BuiltinValueKind::id: #include "swift/AST/Builtins.def" return constantFoldBinaryWithOverflow(BI, Builtin.ID, ResultsInError); #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_OPERATION(id, name, attrs, overload) \ case BuiltinValueKind::id: #include "swift/AST/Builtins.def" return constantFoldBinary(BI, Builtin.ID, ResultsInError); // Fold comparison predicates. #define BUILTIN(id, name, Attrs) #define BUILTIN_BINARY_PREDICATE(id, name, attrs, overload) \ case BuiltinValueKind::id: #include "swift/AST/Builtins.def" return constantFoldCompare(BI, Builtin.ID); case BuiltinValueKind::Trunc: case BuiltinValueKind::ZExt: case BuiltinValueKind::SExt: case BuiltinValueKind::TruncOrBitCast: case BuiltinValueKind::ZExtOrBitCast: case BuiltinValueKind::SExtOrBitCast: { // We can fold if the value being cast is a constant. auto *V = dyn_cast<IntegerLiteralInst>(Args[0]); if (!V) return nullptr; APInt CastResV = constantFoldCast(V->getValue(), Builtin); // Add the literal instruction to represent the result of the cast. SILBuilderWithScope B(BI); return B.createIntegerLiteral(BI->getLoc(), BI->getType(), CastResV); } // Process special builtins that are designed to check for overflows in // integer conversions. case BuiltinValueKind::SToSCheckedTrunc: case BuiltinValueKind::UToUCheckedTrunc: case BuiltinValueKind::SToUCheckedTrunc: case BuiltinValueKind::UToSCheckedTrunc: case BuiltinValueKind::SUCheckedConversion: case BuiltinValueKind::USCheckedConversion: { return constantFoldAndCheckIntegerConversions(BI, Builtin, ResultsInError); } case BuiltinValueKind::IntToFPWithOverflow: { // Get the value. It should be a constant in most cases. // Note, this will not always be a constant, for example, when analyzing // _convertFromBuiltinIntegerLiteral function itself. auto *V = dyn_cast<IntegerLiteralInst>(Args[0]); if (!V) return nullptr; APInt SrcVal = V->getValue(); Type DestTy = Builtin.Types[1]; APFloat TruncVal( DestTy->castTo<BuiltinFloatType>()->getAPFloatSemantics()); APFloat::opStatus ConversionStatus = TruncVal.convertFromAPInt( SrcVal, /*isSigned=*/true, APFloat::rmNearestTiesToEven); SILLocation Loc = BI->getLoc(); const ApplyExpr *CE = Loc.getAsASTNode<ApplyExpr>(); // Check for overflow. if (ConversionStatus & APFloat::opOverflow) { // If we overflow and are not asked for diagnostics, just return nullptr. if (!ResultsInError.hasValue()) return nullptr; SmallString<10> SrcAsString; SrcVal.toString(SrcAsString, /*radix*/10, true /*isSigned*/); // Otherwise emit our diagnostics and then return nullptr. diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_literal_overflow, CE ? CE->getType() : DestTy, SrcAsString); ResultsInError = Optional<bool>(true); return nullptr; } // The call to the builtin should be replaced with the constant value. SILBuilderWithScope B(BI); return B.createFloatLiteral(Loc, BI->getType(), TruncVal); } case BuiltinValueKind::FPTrunc: { // Get the value. It should be a constant in most cases. auto *V = dyn_cast<FloatLiteralInst>(Args[0]); if (!V) return nullptr; APFloat TruncVal = V->getValue(); Type DestTy = Builtin.Types[1]; bool losesInfo; APFloat::opStatus ConversionStatus = TruncVal.convert( DestTy->castTo<BuiltinFloatType>()->getAPFloatSemantics(), APFloat::rmNearestTiesToEven, &losesInfo); SILLocation Loc = BI->getLoc(); // Check if conversion was successful. if (ConversionStatus != APFloat::opStatus::opOK && ConversionStatus != APFloat::opStatus::opInexact) { return nullptr; } // The call to the builtin should be replaced with the constant value. SILBuilderWithScope B(BI); return B.createFloatLiteral(Loc, BI->getType(), TruncVal); } case BuiltinValueKind::AssumeNonNegative: { auto *V = dyn_cast<IntegerLiteralInst>(Args[0]); if (!V) return nullptr; APInt VInt = V->getValue(); if (VInt.isNegative() && ResultsInError.hasValue()) { diagnose(M.getASTContext(), BI->getLoc().getSourceLoc(), diag::wrong_non_negative_assumption, VInt.toString(/*Radix*/ 10, /*Signed*/ true)); ResultsInError = Optional<bool>(true); } return V; } } return nullptr; }
/// \brief Fold arithmetic intrinsics with overflow. static SILInstruction * constantFoldBinaryWithOverflow(BuiltinInst *BI, llvm::Intrinsic::ID ID, bool ReportOverflow, Optional<bool> &ResultsInError) { OperandValueArrayRef Args = BI->getArguments(); assert(Args.size() >= 2); auto *Op1 = dyn_cast<IntegerLiteralInst>(Args[0]); auto *Op2 = dyn_cast<IntegerLiteralInst>(Args[1]); // If either Op1 or Op2 is not a literal, we cannot do anything. if (!Op1 || !Op2) return nullptr; // Calculate the result. APInt LHSInt = Op1->getValue(); APInt RHSInt = Op2->getValue(); bool Overflow; APInt Res = constantFoldBinaryWithOverflow(LHSInt, RHSInt, Overflow, ID); // If we can statically determine that the operation overflows, // warn about it if warnings are not disabled by ResultsInError being null. if (ResultsInError.hasValue() && Overflow && ReportOverflow) { // Try to infer the type of the constant expression that the user operates // on. If the intrinsic was lowered from a call to a function that takes // two arguments of the same type, use the type of the LHS argument. // This would detect '+'/'+=' and such. Type OpType; SILLocation Loc = BI->getLoc(); const ApplyExpr *CE = Loc.getAsASTNode<ApplyExpr>(); SourceRange LHSRange, RHSRange; if (CE) { const auto *Args = dyn_cast_or_null<TupleExpr>(CE->getArg()); if (Args && Args->getNumElements() == 2) { // Look through inout types in order to handle += well. CanType LHSTy = Args->getElement(0)->getType()->getInOutObjectType()-> getCanonicalType(); CanType RHSTy = Args->getElement(1)->getType()->getCanonicalType(); if (LHSTy == RHSTy) OpType = Args->getElement(1)->getType(); LHSRange = Args->getElement(0)->getSourceRange(); RHSRange = Args->getElement(1)->getSourceRange(); } } bool Signed = false; StringRef Operator = "+"; switch (ID) { default: llvm_unreachable("Invalid case"); case llvm::Intrinsic::sadd_with_overflow: Signed = true; break; case llvm::Intrinsic::uadd_with_overflow: break; case llvm::Intrinsic::ssub_with_overflow: Operator = "-"; Signed = true; break; case llvm::Intrinsic::usub_with_overflow: Operator = "-"; break; case llvm::Intrinsic::smul_with_overflow: Operator = "*"; Signed = true; break; case llvm::Intrinsic::umul_with_overflow: Operator = "*"; break; } if (!OpType.isNull()) { diagnose(BI->getModule().getASTContext(), Loc.getSourceLoc(), diag::arithmetic_operation_overflow, LHSInt.toString(/*Radix*/ 10, Signed), Operator, RHSInt.toString(/*Radix*/ 10, Signed), OpType).highlight(LHSRange).highlight(RHSRange); } else { // If we cannot get the type info in an expected way, describe the type. diagnose(BI->getModule().getASTContext(), Loc.getSourceLoc(), diag::arithmetic_operation_overflow_generic_type, LHSInt.toString(/*Radix*/ 10, Signed), Operator, RHSInt.toString(/*Radix*/ 10, Signed), Signed, LHSInt.getBitWidth()).highlight(LHSRange).highlight(RHSRange); } ResultsInError = Optional<bool>(true); } return constructResultWithOverflowTuple(BI, Res, Overflow); }
static SILInstruction * constantFoldAndCheckIntegerConversions(BuiltinInst *BI, const BuiltinInfo &Builtin, Optional<bool> &ResultsInError) { assert(Builtin.ID == BuiltinValueKind::SToSCheckedTrunc || Builtin.ID == BuiltinValueKind::UToUCheckedTrunc || Builtin.ID == BuiltinValueKind::SToUCheckedTrunc || Builtin.ID == BuiltinValueKind::UToSCheckedTrunc || Builtin.ID == BuiltinValueKind::SUCheckedConversion || Builtin.ID == BuiltinValueKind::USCheckedConversion); // Check if we are converting a constant integer. OperandValueArrayRef Args = BI->getArguments(); auto *V = dyn_cast<IntegerLiteralInst>(Args[0]); if (!V) return nullptr; APInt SrcVal = V->getValue(); // Get source type and bit width. Type SrcTy = Builtin.Types[0]; uint32_t SrcBitWidth = Builtin.Types[0]->castTo<BuiltinIntegerType>()->getGreatestWidth(); // Compute the destination (for SrcBitWidth < DestBitWidth) and enough info // to check for overflow. APInt Result; bool OverflowError; Type DstTy; // Process conversions signed <-> unsigned for same size integers. if (Builtin.ID == BuiltinValueKind::SUCheckedConversion || Builtin.ID == BuiltinValueKind::USCheckedConversion) { DstTy = SrcTy; Result = SrcVal; // Report an error if the sign bit is set. OverflowError = SrcVal.isNegative(); // Process truncation from unsigned to signed. } else if (Builtin.ID != BuiltinValueKind::UToSCheckedTrunc) { assert(Builtin.Types.size() == 2); DstTy = Builtin.Types[1]; uint32_t DstBitWidth = DstTy->castTo<BuiltinIntegerType>()->getGreatestWidth(); // Result = trunc_IntFrom_IntTo(Val) // For signed destination: // sext_IntFrom(Result) == Val ? Result : overflow_error // For signed destination: // zext_IntFrom(Result) == Val ? Result : overflow_error Result = SrcVal.trunc(DstBitWidth); // Get the signedness of the destination. bool Signed = (Builtin.ID == BuiltinValueKind::SToSCheckedTrunc); APInt Ext = Signed ? Result.sext(SrcBitWidth) : Result.zext(SrcBitWidth); OverflowError = (SrcVal != Ext); // Process the rest of truncations. } else { assert(Builtin.Types.size() == 2); DstTy = Builtin.Types[1]; uint32_t DstBitWidth = Builtin.Types[1]->castTo<BuiltinIntegerType>()->getGreatestWidth(); // Compute the destination (for SrcBitWidth < DestBitWidth): // Result = trunc_IntTo(Val) // Trunc = trunc_'IntTo-1bit'(Val) // zext_IntFrom(Trunc) == Val ? Result : overflow_error Result = SrcVal.trunc(DstBitWidth); APInt TruncVal = SrcVal.trunc(DstBitWidth - 1); OverflowError = (SrcVal != TruncVal.zext(SrcBitWidth)); } // Check for overflow. if (OverflowError) { // If we are not asked to emit overflow diagnostics, just return nullptr on // overflow. if (!ResultsInError.hasValue()) return nullptr; SILLocation Loc = BI->getLoc(); SILModule &M = BI->getModule(); const ApplyExpr *CE = Loc.getAsASTNode<ApplyExpr>(); Type UserSrcTy; Type UserDstTy; // Primitive heuristics to get the user-written type. // Eventually we might be able to use SILLocation (when it contains info // about inlined call chains). if (CE) { if (const TupleType *RTy = CE->getArg()->getType()->getAs<TupleType>()) { if (RTy->getNumElements() == 1) { UserSrcTy = RTy->getElementType(0); UserDstTy = CE->getType(); } } else { UserSrcTy = CE->getArg()->getType(); UserDstTy = CE->getType(); } } // Assume that we are converting from a literal if the Source size is // 2048. Is there a better way to identify conversions from literals? bool Literal = (SrcBitWidth == 2048); // FIXME: This will prevent hard error in cases the error is coming // from ObjC interoperability code. Currently, we treat NSUInteger as // Int. if (Loc.getSourceLoc().isInvalid()) { // Otherwise emit the appropriate diagnostic and set ResultsInError. if (Literal) diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_literal_overflow_warn, UserDstTy.isNull() ? DstTy : UserDstTy); else diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_conversion_overflow_warn, UserSrcTy.isNull() ? SrcTy : UserSrcTy, UserDstTy.isNull() ? DstTy : UserDstTy); ResultsInError = Optional<bool>(true); return nullptr; } // Otherwise report the overflow error. if (Literal) { bool SrcTySigned, DstTySigned; std::tie(SrcTySigned, DstTySigned) = getTypeSignedness(Builtin); SmallString<10> SrcAsString; SrcVal.toString(SrcAsString, /*radix*/10, SrcTySigned); // Try to print user-visible types if they are available. if (!UserDstTy.isNull()) { auto diagID = diag::integer_literal_overflow; // If this is a negative literal in an unsigned type, use a specific // diagnostic. if (SrcTySigned && !DstTySigned && SrcVal.isNegative()) diagID = diag::negative_integer_literal_overflow_unsigned; diagnose(M.getASTContext(), Loc.getSourceLoc(), diagID, UserDstTy, SrcAsString); // Otherwise, print the Builtin Types. } else { bool SrcTySigned, DstTySigned; std::tie(SrcTySigned, DstTySigned) = getTypeSignedness(Builtin); diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_literal_overflow_builtin_types, DstTySigned, DstTy, SrcAsString); } } else { if (Builtin.ID == BuiltinValueKind::SUCheckedConversion) { diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_conversion_sign_error, UserDstTy.isNull() ? DstTy : UserDstTy); } else { // Try to print user-visible types if they are available. if (!UserSrcTy.isNull()) { diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_conversion_overflow, UserSrcTy, UserDstTy); // Otherwise, print the Builtin Types. } else { // Since builtin types are sign-agnostic, print the signedness // separately. bool SrcTySigned, DstTySigned; std::tie(SrcTySigned, DstTySigned) = getTypeSignedness(Builtin); diagnose(M.getASTContext(), Loc.getSourceLoc(), diag::integer_conversion_overflow_builtin_types, SrcTySigned, SrcTy, DstTySigned, DstTy); } } } ResultsInError = Optional<bool>(true); return nullptr; } // The call to the builtin should be replaced with the constant value. return constructResultWithOverflowTuple(BI, Result, false); }
static SILInstruction * constantFoldAndCheckDivision(BuiltinInst *BI, BuiltinValueKind ID, Optional<bool> &ResultsInError) { assert(ID == BuiltinValueKind::SDiv || ID == BuiltinValueKind::SRem || ID == BuiltinValueKind::UDiv || ID == BuiltinValueKind::URem); OperandValueArrayRef Args = BI->getArguments(); SILModule &M = BI->getModule(); // Get the denominator. auto *Denom = dyn_cast<IntegerLiteralInst>(Args[1]); if (!Denom) return nullptr; APInt DenomVal = Denom->getValue(); // If the denominator is zero... if (DenomVal == 0) { // And if we are not asked to report errors, just return nullptr. if (!ResultsInError.hasValue()) return nullptr; // Otherwise emit a diagnosis error and set ResultsInError to true. diagnose(M.getASTContext(), BI->getLoc().getSourceLoc(), diag::division_by_zero); ResultsInError = Optional<bool>(true); return nullptr; } // Get the numerator. auto *Num = dyn_cast<IntegerLiteralInst>(Args[0]); if (!Num) return nullptr; APInt NumVal = Num->getValue(); bool Overflowed; APInt ResVal = constantFoldDiv(NumVal, DenomVal, Overflowed, ID); // If we overflowed... if (Overflowed) { // And we are not asked to produce diagnostics, just return nullptr... if (!ResultsInError.hasValue()) return nullptr; bool IsRem = ID == BuiltinValueKind::SRem || ID == BuiltinValueKind::URem; // Otherwise emit the diagnostic, set ResultsInError to be true, and return // nullptr. diagnose(M.getASTContext(), BI->getLoc().getSourceLoc(), diag::division_overflow, NumVal.toString(/*Radix*/ 10, /*Signed*/true), IsRem ? "%" : "/", DenomVal.toString(/*Radix*/ 10, /*Signed*/true)); ResultsInError = Optional<bool>(true); return nullptr; } // Add the literal instruction to represent the result of the division. SILBuilderWithScope B(BI); return B.createIntegerLiteral(BI->getLoc(), BI->getType(), ResVal); }