This reverts commit (@259587). It needs some further discussions.
llvm-svn: 259629
rrkUndefBasePtr,
rrkVariantBasePtr,
rrkNonAffineAccess,
+ rrkDifferentElementSize,
rrkLastAffFunc,
rrkLoopBound,
};
//===----------------------------------------------------------------------===//
+/// @brief Report array accesses with differing element size.
+class ReportDifferentArrayElementSize : public ReportAffFunc {
+ //===--------------------------------------------------------------------===//
+
+ // The base pointer of the memory access.
+ const Value *BaseValue;
+
+public:
+ ReportDifferentArrayElementSize(const Instruction *Inst, const Value *V)
+ : ReportAffFunc(rrkDifferentElementSize, Inst), BaseValue(V) {}
+
+ /// @name LLVM-RTTI interface
+ //@{
+ static bool classof(const RejectReason *RR);
+ //@}
+
+ /// @name RejectReason interface
+ //@{
+ virtual std::string getMessage() const override;
+ virtual std::string getEndUserMessage() const override;
+ //@}
+};
+
+//===----------------------------------------------------------------------===//
/// @brief Captures errors with non affine loop bounds.
class ReportLoopBound : public RejectReason {
//===--------------------------------------------------------------------===//
/// @param A vector of array sizes where the rightmost array sizes need to
/// match the innermost array sizes already defined in SAI.
/// @returns Returns true if the update was successful, otherwise false.
- bool updateSizes(ArrayRef<const SCEV *> Sizes, Type *ElementType);
+ bool updateSizes(ArrayRef<const SCEV *> Sizes);
/// @brief Destructor to free the isl id of the base pointer.
~ScopArrayInfo();
/// @brief Subscript expression for each dimension.
SmallVector<const SCEV *, 4> Subscripts;
- /// @brief Relation from statement instances to the accessed array elements.
- ///
- /// In the common case this relation is a function that maps a set of loop
- /// indices to the memory address from which a value is loaded.
- ///
- /// For example:
- /// for i
- /// for j
- /// S: A[i + 3 j] = ...
- ///
- /// => { S[i,j] -> A[i + 3j] }
- ///
- /// For cases where the access function is not known, the access relation may
- /// also be a one to all mapping { S[i,j] -> A[o] } describing that any
- /// element accessible through A might be accessed.
- ///
- /// In case a larger element is loaded from an array that may also contain
- /// smaller elements, the access function may relate model multiple smaller
- /// reads. In this case, the lexicograph smallest element is the memory
- /// address from which the largest element needs to be loaded from.
+ /// @brief Relation from statment instances to the accessed array elements.
isl_map *AccessRelation;
/// @brief Updated access relation read from JSCOP file.
AccessFunction = SE->getMinusSCEV(AccessFunction, BasePointer);
const SCEV *Size = SE->getElementSize(Inst);
- Context.ElementSize[BasePointer] = Size;
+ if (Context.ElementSize.count(BasePointer)) {
+ if (Context.ElementSize[BasePointer] != Size)
+ return invalid<ReportDifferentArrayElementSize>(Context, /*Assert=*/true,
+ Inst, BaseValue);
+ } else {
+ Context.ElementSize[BasePointer] = Size;
+ }
bool isVariantInNonAffineLoop = false;
SetVector<const Loop *> Loops;
}
//===----------------------------------------------------------------------===//
+// ReportDifferentArrayElementSize
+
+std::string ReportDifferentArrayElementSize::getMessage() const {
+ return "Access to one array through data types of different size";
+}
+
+bool ReportDifferentArrayElementSize::classof(const RejectReason *RR) {
+ return RR->getKind() == rrkDifferentElementSize;
+}
+
+std::string ReportDifferentArrayElementSize::getEndUserMessage() const {
+ llvm::StringRef BaseName = BaseValue->getName();
+ std::string Name = (BaseName.size() > 0) ? BaseName : "UNKNOWN";
+ return "The array \"" + Name + "\" is accessed through elements that differ "
+ "in size";
+}
+
+//===----------------------------------------------------------------------===//
// ReportNonAffineAccess.
std::string ReportNonAffineAccess::getMessage() const {
getIslCompatibleName("MemRef_", BasePtr, Kind == MK_PHI ? "__phi" : "");
Id = isl_id_alloc(Ctx, BasePtrName.c_str(), this);
- updateSizes(Sizes, ElementType);
+ updateSizes(Sizes);
BasePtrOriginSAI = identifyBasePtrOriginSAI(S, BasePtr);
if (BasePtrOriginSAI)
const_cast<ScopArrayInfo *>(BasePtrOriginSAI)->addDerivedSAI(this);
return Space;
}
-bool ScopArrayInfo::updateSizes(ArrayRef<const SCEV *> NewSizes,
- Type *NewElementType) {
- auto OldElementSize = DL.getTypeAllocSize(ElementType);
- auto NewElementSize = DL.getTypeAllocSize(NewElementType);
-
- if (OldElementSize != NewElementSize) {
- if (OldElementSize < NewElementSize &&
- NewElementSize % OldElementSize == 0) {
- ; // fallthrough
- } else if (NewElementSize < OldElementSize &&
- OldElementSize % NewElementSize == 0) {
- ElementType = NewElementType;
- } else {
- return false;
- }
- }
-
+bool ScopArrayInfo::updateSizes(ArrayRef<const SCEV *> NewSizes) {
int SharedDims = std::min(NewSizes.size(), DimensionSizes.size());
int ExtraDimsNew = NewSizes.size() - SharedDims;
int ExtraDimsOld = DimensionSizes.size() - SharedDims;
auto DimsAccess = isl_space_dim(AccessSpace, isl_dim_set);
auto DimsMissing = DimsArray - DimsAccess;
- auto Map = isl_map_from_domain_and_range(
- isl_set_universe(AccessSpace),
- isl_set_universe(isl_space_copy(ArraySpace)));
+ auto Map = isl_map_from_domain_and_range(isl_set_universe(AccessSpace),
+ isl_set_universe(ArraySpace));
for (unsigned i = 0; i < DimsMissing; i++)
Map = isl_map_fix_si(Map, isl_dim_out, i, 0);
AccessRelation = isl_map_apply_range(AccessRelation, Map);
- // Introduce multi-element accesses in case the type loaded by this memory
- // access is larger than the canonical element type of the array.
- //
- // An access ((float *)A)[i] to an array char *A is modeled as
- // {[i] -> A[o] : 4 i <= o <= 4 i + 3
- unsigned ArrayElemSize = getScopArrayInfo()->getElemSizeInBytes();
- if (ElemBytes > ArrayElemSize && ElemBytes % ArrayElemSize == 0) {
- auto Map = isl_map_from_domain_and_range(
- isl_set_universe(isl_space_copy(ArraySpace)),
- isl_set_universe(isl_space_copy(ArraySpace)));
- for (unsigned i = 0; i < DimsArray - 1; i++)
- Map = isl_map_equate(Map, isl_dim_in, i, isl_dim_out, i);
-
- isl_ctx *Ctx;
- isl_constraint *C;
- isl_local_space *LS;
-
- LS = isl_local_space_from_space(isl_map_get_space(Map));
- Ctx = isl_map_get_ctx(Map);
- int Num = ElemBytes / getScopArrayInfo()->getElemSizeInBytes();
-
- C = isl_constraint_alloc_inequality(isl_local_space_copy(LS));
- C = isl_constraint_set_constant_val(C, isl_val_int_from_si(Ctx, Num - 1));
- C = isl_constraint_set_coefficient_si(C, isl_dim_in,
- DimsArray - 1 - DimsMissing, Num);
- C = isl_constraint_set_coefficient_si(C, isl_dim_out, DimsArray - 1, -1);
- Map = isl_map_add_constraint(Map, C);
-
- C = isl_constraint_alloc_inequality(LS);
- C = isl_constraint_set_coefficient_si(C, isl_dim_in,
- DimsArray - 1 - DimsMissing, -Num);
- C = isl_constraint_set_coefficient_si(C, isl_dim_out, DimsArray - 1, 1);
- C = isl_constraint_set_constant_val(C, isl_val_int_from_si(Ctx, 0));
- Map = isl_map_add_constraint(Map, C);
- AccessRelation = isl_map_apply_range(AccessRelation, Map);
- }
-
- isl_space_free(ArraySpace);
-
assumeNoOutOfBound();
}
USchedule = isl_union_map_intersect_domain(USchedule, UDomain);
Schedule = isl_map_from_union_map(USchedule);
ScheduledAccRel = isl_map_apply_domain(getAccessRelation(), Schedule);
-
- // For multi-element accesses we always use the lowest memory location as the
- // actual element that is accessed.
- ScheduledAccRel = isl_map_lexmin(ScheduledAccRel);
return isl_pw_multi_aff_from_map(ScheduledAccRel);
}
} else {
// In case of mismatching array sizes, we bail out by setting the run-time
// context to false.
- if (!SAI->updateSizes(Sizes, ElementType))
+ if (!SAI->updateSizes(Sizes))
invalidate(DELINEARIZATION, DebugLoc());
}
return SAI.get();
OldPtrTy = PointerType::get(OldPtrTy->getElementType(),
NewPtrTy->getPointerAddressSpace());
- if (OldPtrTy != NewPtrTy)
+ if (OldPtrTy != NewPtrTy) {
+ assert(OldPtrTy->getPointerElementType()->getPrimitiveSizeInBits() ==
+ NewPtrTy->getPointerElementType()->getPrimitiveSizeInBits() &&
+ "Pointer types to elements with different size found");
Address = Builder.CreateBitOrPointerCast(Address, OldPtrTy);
+ }
return Address;
}
+++ /dev/null
-; RUN: opt %loadPolly -polly-import-jscop -polly-import-jscop-dir=%S \
-; RUN: -polly-codegen -S < %s | FileCheck %s
-;
-; // Check that accessing one array with different types works.
-; void multiple_types(char *Short, char *Float, char *Double) {
-; for (long i = 0; i < 100; i++) {
-; Short[i] = *(short *)&Short[2 * i];
-; Float[i] = *(float *)&Float[4 * i];
-; Double[i] = *(double *)&Double[8 * i];
-; }
-; }
-
-; Short[0]
-; CHECK: %polly.access.Short10 = getelementptr i8, i8* %Short, i64 0
-; CHECK: %12 = bitcast i8* %polly.access.Short10 to i16*
-; CHECK: %tmp5_p_scalar_ = load i16, i16* %12
-
-; Float[8 * i]
-; CHECK: %13 = mul nsw i64 8, %polly.indvar
-; CHECK: %polly.access.Float11 = getelementptr i8, i8* %Float, i64 %13
-; CHECK: %14 = bitcast i8* %polly.access.Float11 to float*
-; CHECK: %tmp11_p_scalar_ = load float, float* %14
-
-; Double[8]
-; CHECK: %polly.access.Double13 = getelementptr i8, i8* %Double, i64 8
-; CHECK: %15 = bitcast i8* %polly.access.Double13 to double*
-; CHECK: %tmp17_p_scalar_ = load double, double* %15
-
-target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
-
-define void @multiple_types(i8* %Short, i8* %Float, i8* %Double) {
-bb:
- br label %bb1
-
-bb1: ; preds = %bb20, %bb
- %i.0 = phi i64 [ 0, %bb ], [ %tmp21, %bb20 ]
- %exitcond = icmp ne i64 %i.0, 100
- br i1 %exitcond, label %bb2, label %bb22
-
-bb2: ; preds = %bb1
- %tmp = shl nsw i64 %i.0, 1
- %tmp3 = getelementptr inbounds i8, i8* %Short, i64 %tmp
- %tmp4 = bitcast i8* %tmp3 to i16*
- %tmp5 = load i16, i16* %tmp4, align 2
- %tmp6 = trunc i16 %tmp5 to i8
- %tmp7 = getelementptr inbounds i8, i8* %Short, i64 %i.0
- store i8 %tmp6, i8* %tmp7, align 1
- %tmp8 = shl nsw i64 %i.0, 2
- %tmp9 = getelementptr inbounds i8, i8* %Float, i64 %tmp8
- %tmp10 = bitcast i8* %tmp9 to float*
- %tmp11 = load float, float* %tmp10, align 4
- %tmp12 = fptosi float %tmp11 to i8
- %tmp13 = getelementptr inbounds i8, i8* %Float, i64 %i.0
- store i8 %tmp12, i8* %tmp13, align 1
- %tmp14 = shl nsw i64 %i.0, 3
- %tmp15 = getelementptr inbounds i8, i8* %Double, i64 %tmp14
- %tmp16 = bitcast i8* %tmp15 to double*
- %tmp17 = load double, double* %tmp16, align 8
- %tmp18 = fptosi double %tmp17 to i8
- %tmp19 = getelementptr inbounds i8, i8* %Double, i64 %i.0
- store i8 %tmp18, i8* %tmp19, align 1
- br label %bb20
-
-bb20: ; preds = %bb2
- %tmp21 = add nuw nsw i64 %i.0, 1
- br label %bb1
-
-bb22: ; preds = %bb1
- ret void
-}
+++ /dev/null
-{
- "context" : "{ : }",
- "name" : "bb1 => bb22",
- "statements" : [
- {
- "accesses" : [
- {
- "kind" : "read",
- "relation" : "{ Stmt_bb2[i0] -> MemRef_Short[0]}"
- },
- {
- "kind" : "write",
- "relation" : "{ Stmt_bb2[i0] -> MemRef_Short[i0] }"
- },
- {
- "kind" : "read",
- "relation" : "{ Stmt_bb2[i0] -> MemRef_Float[o0] : 8i0 <= o0 <= 3 + 8i0 }"
- },
- {
- "kind" : "write",
- "relation" : "{ Stmt_bb2[i0] -> MemRef_Float[i0] }"
- },
- {
- "kind" : "read",
- "relation" : "{ Stmt_bb2[i0] -> MemRef_Double[8]}"
- },
- {
- "kind" : "write",
- "relation" : "{ Stmt_bb2[i0] -> MemRef_Double[i0] }"
- }
- ],
- "domain" : "{ Stmt_bb2[i0] : 0 <= i0 <= 99 }",
- "name" : "Stmt_bb2",
- "schedule" : "{ Stmt_bb2[i0] -> [i0] }"
- }
- ]
-}
--- /dev/null
+; RUN: opt %loadPolly -pass-remarks-missed="polly-detect" -polly-detect-track-failures -polly-detect -analyze < %s 2>&1| FileCheck %s
+
+; 1 void differenttypes(char *A)
+; 2 {
+; 3 for (long i = 0; i < 1024; ++i)
+; 4 ((float*)A)[i] = ((double*)A)[i];
+; 5 }
+
+; CHECK: remark: /tmp/test.c:3:20: The following errors keep this region from being a Scop.
+; CHECK-NEXT: remark: /tmp/test.c:4:14: The array "A" is accessed through elements that differ in size
+; CHECK-NEXT: remark: /tmp/test.c:4:32: Invalid Scop candidate ends here.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define void @differenttypes(i8* nocapture %A) !dbg !4 {
+entry:
+ br label %for.body, !dbg !10
+
+for.body: ; preds = %for.body, %entry
+ %i.05 = phi i64 [ 0, %entry ], [ %tmp11, %for.body ]
+ %tmp = shl i64 %i.05, 3, !dbg !15
+ %uglygep = getelementptr i8, i8* %A, i64 %tmp
+ %arrayidx = bitcast i8* %uglygep to double*, !dbg !16
+ %tmp9 = shl i64 %i.05, 2, !dbg !15
+ %uglygep7 = getelementptr i8, i8* %A, i64 %tmp9
+ %arrayidx1 = bitcast i8* %uglygep7 to float*, !dbg !17
+ %tmp10 = load double, double* %arrayidx, align 8, !dbg !16, !tbaa !18
+ %conv = fptrunc double %tmp10 to float, !dbg !16
+ store float %conv, float* %arrayidx1, align 4, !dbg !17, !tbaa !22
+ %tmp11 = add nsw i64 %i.05, 1, !dbg !24
+ %exitcond = icmp eq i64 %tmp11, 1024, !dbg !10
+ br i1 %exitcond, label %for.end, label %for.body, !dbg !10
+
+for.end: ; preds = %for.body
+ ret void, !dbg !25
+}
+
+!llvm.dbg.cu = !{!0}
+!llvm.module.flags = !{!7, !8}
+!llvm.ident = !{!9}
+
+!0 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.6.0 ", isOptimized: true, emissionKind: 2, file: !1, enums: !2, retainedTypes: !2, subprograms: !3, globals: !2, imports: !2)
+!1 = !DIFile(filename: "/tmp/test.c", directory: "/home/grosser/Projects/polly/git/tools/polly/test/ScopDetectionDiagnostics")
+!2 = !{}
+!3 = !{!4}
+!4 = distinct !DISubprogram(name: "differenttypes", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, scopeLine: 2, file: !1, scope: !5, type: !6, variables: !2)
+!5 = !DIFile(filename: "/tmp/test.c", directory: "/home/grosser/Projects/polly/git/tools/polly/test/ScopDetectionDiagnostics")
+!6 = !DISubroutineType(types: !2)
+!7 = !{i32 2, !"Dwarf Version", i32 4}
+!8 = !{i32 2, !"Debug Info Version", i32 3}
+!9 = !{!"clang version 3.6.0 "}
+!10 = !DILocation(line: 3, column: 20, scope: !11)
+!11 = !DILexicalBlockFile(discriminator: 2, file: !1, scope: !12)
+!12 = !DILexicalBlockFile(discriminator: 1, file: !1, scope: !13)
+!13 = distinct !DILexicalBlock(line: 3, column: 3, file: !1, scope: !14)
+!14 = distinct !DILexicalBlock(line: 3, column: 3, file: !1, scope: !4)
+!15 = !DILocation(line: 4, column: 32, scope: !13)
+!16 = !DILocation(line: 4, column: 22, scope: !13)
+!17 = !DILocation(line: 4, column: 14, scope: !13)
+!18 = !{!19, !19, i64 0}
+!19 = !{!"double", !20, i64 0}
+!20 = !{!"omnipotent char", !21, i64 0}
+!21 = !{!"Simple C/C++ TBAA"}
+!22 = !{!23, !23, i64 0}
+!23 = !{!"float", !20, i64 0}
+!24 = !DILocation(line: 3, column: 30, scope: !13)
+!25 = !DILocation(line: 5, column: 1, scope: !4)
+++ /dev/null
-; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
-;
-; // Check that accessing one array with different types works.
-; void multiple_types(char *Short, char *Float, char *Double) {
-; for (long i = 0; i < 100; i++) {
-; Short[i] = *(short *)&Short[i];
-; Float[i] = *(float *)&Float[i];
-; Double[i] = *(double *)&Double[i];
-; }
-; }
-;
-; CHECK-NOT: Statements
-
-target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
-
-define void @multiple_types(i8* %Short, i8* %Float, i8* %Double) {
-bb:
- br label %bb1
-
-bb1: ; preds = %bb17, %bb
- %i.0 = phi i64 [ 0, %bb ], [ %tmp18, %bb17 ]
- %exitcond = icmp ne i64 %i.0, 100
- br i1 %exitcond, label %bb2, label %bb19
-
-bb2: ; preds = %bb1
- %tmp = getelementptr inbounds i8, i8* %Short, i64 %i.0
- %tmp3 = bitcast i8* %tmp to i16*
- %tmp4 = load i16, i16* %tmp3, align 2
- %tmp5 = trunc i16 %tmp4 to i8
- %tmp6 = getelementptr inbounds i8, i8* %Short, i64 %i.0
- store i8 %tmp5, i8* %tmp6, align 1
- %tmp7 = getelementptr inbounds i8, i8* %Float, i64 %i.0
- %tmp8 = bitcast i8* %tmp7 to float*
- %tmp9 = load float, float* %tmp8, align 4
- %tmp10 = fptosi float %tmp9 to i8
- %tmp11 = getelementptr inbounds i8, i8* %Float, i64 %i.0
- store i8 %tmp10, i8* %tmp11, align 1
- %tmp12 = getelementptr inbounds i8, i8* %Double, i64 %i.0
- %tmp13 = bitcast i8* %tmp12 to double*
- %tmp14 = load double, double* %tmp13, align 8
- %tmp15 = fptosi double %tmp14 to i8
- %tmp16 = getelementptr inbounds i8, i8* %Double, i64 %i.0
- store i8 %tmp15, i8* %tmp16, align 1
- br label %bb17
-
-bb17: ; preds = %bb2
- %tmp18 = add nuw nsw i64 %i.0, 1
- br label %bb1
-
-bb19: ; preds = %bb1
- ret void
-}
+++ /dev/null
-; RUN: opt %loadPolly -polly-scops -analyze < %s | FileCheck %s
-;
-; // Check that accessing one array with different types works.
-; void multiple_types(char *Short, char *Float, char *Double) {
-; for (long i = 0; i < 100; i++) {
-; Short[i] = *(short *)&Short[2 * i];
-; Float[i] = *(float *)&Float[4 * i];
-; Double[i] = *(double *)&Double[8 * i];
-; }
-; }
-
-; CHECK: Statements {
-; CHECK-NEXT: Stmt_bb2
-; CHECK-NEXT: Domain :=
-; CHECK-NEXT: { Stmt_bb2[i0] : 0 <= i0 <= 99 };
-; CHECK-NEXT: Schedule :=
-; CHECK-NEXT: { Stmt_bb2[i0] -> [i0] };
-; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
-; CHECK-NEXT: { Stmt_bb2[i0] -> MemRef_Short[o0] : 2i0 <= o0 <= 1 + 2i0 };
-; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
-; CHECK-NEXT: { Stmt_bb2[i0] -> MemRef_Short[i0] };
-; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
-; CHECK-NEXT: { Stmt_bb2[i0] -> MemRef_Float[o0] : 4i0 <= o0 <= 3 + 4i0 };
-; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
-; CHECK-NEXT: { Stmt_bb2[i0] -> MemRef_Float[i0] };
-; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0]
-; CHECK-NEXT: { Stmt_bb2[i0] -> MemRef_Double[o0] : 8i0 <= o0 <= 7 + 8i0 };
-; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0]
-; CHECK-NEXT: { Stmt_bb2[i0] -> MemRef_Double[i0] };
-; CHECK-NEXT: }
-
-target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
-
-define void @multiple_types(i8* %Short, i8* %Float, i8* %Double) {
-bb:
- br label %bb1
-
-bb1: ; preds = %bb20, %bb
- %i.0 = phi i64 [ 0, %bb ], [ %tmp21, %bb20 ]
- %exitcond = icmp ne i64 %i.0, 100
- br i1 %exitcond, label %bb2, label %bb22
-
-bb2: ; preds = %bb1
- %tmp = shl nsw i64 %i.0, 1
- %tmp3 = getelementptr inbounds i8, i8* %Short, i64 %tmp
- %tmp4 = bitcast i8* %tmp3 to i16*
- %tmp5 = load i16, i16* %tmp4, align 2
- %tmp6 = trunc i16 %tmp5 to i8
- %tmp7 = getelementptr inbounds i8, i8* %Short, i64 %i.0
- store i8 %tmp6, i8* %tmp7, align 1
- %tmp8 = shl nsw i64 %i.0, 2
- %tmp9 = getelementptr inbounds i8, i8* %Float, i64 %tmp8
- %tmp10 = bitcast i8* %tmp9 to float*
- %tmp11 = load float, float* %tmp10, align 4
- %tmp12 = fptosi float %tmp11 to i8
- %tmp13 = getelementptr inbounds i8, i8* %Float, i64 %i.0
- store i8 %tmp12, i8* %tmp13, align 1
- %tmp14 = shl nsw i64 %i.0, 3
- %tmp15 = getelementptr inbounds i8, i8* %Double, i64 %tmp14
- %tmp16 = bitcast i8* %tmp15 to double*
- %tmp17 = load double, double* %tmp16, align 8
- %tmp18 = fptosi double %tmp17 to i8
- %tmp19 = getelementptr inbounds i8, i8* %Double, i64 %i.0
- store i8 %tmp18, i8* %tmp19, align 1
- br label %bb20
-
-bb20: ; preds = %bb2
- %tmp21 = add nuw nsw i64 %i.0, 1
- br label %bb1
-
-bb22: ; preds = %bb1
- ret void
-}