Index: include/polly/ScopInfo.h =================================================================== --- include/polly/ScopInfo.h +++ include/polly/ScopInfo.h @@ -64,6 +64,7 @@ class Scop; class ScopStmt; class ScopInfo; +class ScopArrayInfo; typedef DenseMap OutgoingValueMapTy; @@ -93,6 +94,23 @@ typedef std::deque AccFuncSetType; typedef std::map AccFuncMapType; +/// @brief Helper struct to id a memory access. +struct AccessId { + static const MemoryAccess *getMA(__isl_take isl_id *Id); + static const ScopArrayInfo *getSAI(__isl_take isl_id *Id); + + static isl_id *get(const MemoryAccess *MA); + static isl_id *get(const ScopArrayInfo *SAI, const std::string &Name, + Scop *S); + +private: + AccessId(const MemoryAccess *MA) : MA(MA), SAI(nullptr) {} + AccessId(const ScopArrayInfo *SAI) : MA(nullptr), SAI(SAI) {} + + const MemoryAccess *const MA; + const ScopArrayInfo *const SAI; +}; + /// @brief A class to store information about arrays in the SCoP. /// /// Objects are accessible via the ScoP, MemoryAccess or the id associated with @@ -690,6 +708,9 @@ /// @brief Is this a write memory access? bool isWrite() const { return isMustWrite() || isMayWrite(); } + /// @brief Return the alignment of this access. + unsigned getAlignment() const; + /// @brief Check if a new access relation was imported or set by a pass. bool hasNewAccessRelation() const { return NewAccessRelation; } Index: lib/Analysis/ScopInfo.cpp =================================================================== --- lib/Analysis/ScopInfo.cpp +++ lib/Analysis/ScopInfo.cpp @@ -174,13 +174,49 @@ ScopArrayInfo::MK_Array); } +static void freeAccessId(void *User) { delete static_cast(User); } + +isl_id *AccessId::get(const MemoryAccess *MA) { + auto *Payload = new AccessId(MA); + auto *ArrayId = MA->getArrayId(); + auto *Id = + isl_id_alloc(isl_id_get_ctx(ArrayId), isl_id_get_name(ArrayId), Payload); + Id = isl_id_set_free_user(Id, freeAccessId); + isl_id_free(ArrayId); + return Id; +} + +isl_id *AccessId::get(const ScopArrayInfo *SAI, const std::string &Name, + Scop *S) { + auto *Payload = new AccessId(SAI); + auto *Id = isl_id_alloc(S->getIslCtx(), Name.c_str(), Payload); + Id = isl_id_set_free_user(Id, freeAccessId); + return Id; +} + +const MemoryAccess *AccessId::getMA(isl_id *Id) { + void *User = isl_id_get_user(Id); + auto *AId = static_cast(User); + assert(AId && (AId->MA || AId->SAI)); + isl_id_free(Id); + return AId->MA; +} + +const ScopArrayInfo *AccessId::getSAI(isl_id *Id) { + void *User = isl_id_get_user(Id); + auto *AId = static_cast(User); + assert(AId && (AId->MA || AId->SAI)); + isl_id_free(Id); + return AId->SAI; +} + ScopArrayInfo::ScopArrayInfo(Value *BasePtr, Type *ElementType, isl_ctx *Ctx, ArrayRef Sizes, enum MemoryKind Kind, const DataLayout &DL, Scop *S) : BasePtr(BasePtr), ElementType(ElementType), Kind(Kind), DL(DL), S(*S) { std::string BasePtrName = getIslCompatibleName("MemRef_", BasePtr, Kind == MK_PHI ? "__phi" : ""); - Id = isl_id_alloc(Ctx, BasePtrName.c_str(), this); + Id = AccessId::get(this, BasePtrName, S); updateSizes(Sizes, ElementType); BasePtrOriginSAI = identifyBasePtrOriginSAI(S, BasePtr); @@ -474,18 +510,24 @@ const ScopArrayInfo *MemoryAccess::getScopArrayInfo() const { isl_id *ArrayId = getArrayId(); - void *User = isl_id_get_user(ArrayId); - const ScopArrayInfo *SAI = static_cast(User); - isl_id_free(ArrayId); - return SAI; + return AccessId::getSAI(ArrayId); } __isl_give isl_id *MemoryAccess::getArrayId() const { return isl_map_get_tuple_id(AccessRelation, isl_dim_out); } +unsigned MemoryAccess::getAlignment() const { + if (!isArrayKind()) + return 0; + + return MemAccInst(getAccessInstruction()).getAlignment(); +} + __isl_give isl_map *MemoryAccess::getAddressFunction() const { - return isl_map_lexmin(getAccessRelation()); + auto *AddressFunction = isl_map_lexmin(getAccessRelation()); + return isl_map_set_tuple_id(AddressFunction, isl_dim_out, + AccessId::get(this)); } __isl_give isl_pw_multi_aff *MemoryAccess::applyScheduleToAccessRelation( Index: lib/CodeGen/IslExprBuilder.cpp =================================================================== --- lib/CodeGen/IslExprBuilder.cpp +++ lib/CodeGen/IslExprBuilder.cpp @@ -103,28 +103,29 @@ "We need at least two operands to create a member access."); Value *Base, *IndexOp, *Access; - isl_ast_expr *BaseExpr; - isl_id *BaseId; - BaseExpr = isl_ast_expr_get_op_arg(Expr, 0); - BaseId = isl_ast_expr_get_id(BaseExpr); + auto *BaseExpr = isl_ast_expr_get_op_arg(Expr, 0); + auto *MA = AccessId::getMA(isl_ast_expr_get_id(BaseExpr)); + assert((!MA || MA->isArrayKind()) && "Scalars have no address of"); + + auto *SAI = MA ? MA->getScopArrayInfo() + : AccessId::getSAI(isl_ast_expr_get_id(BaseExpr)); + assert(SAI && "ScopArrayInfo object is needed to create address of expr"); isl_ast_expr_free(BaseExpr); - const ScopArrayInfo *SAI = ScopArrayInfo::getFromId(BaseId); Base = SAI->getBasePtr(); - if (auto NewBase = GlobalMap.lookup(Base)) Base = NewBase; assert(Base->getType()->isPointerTy() && "Access base should be a pointer"); StringRef BaseName = Base->getName(); - auto PointerTy = PointerType::get(SAI->getElementType(), - Base->getType()->getPointerAddressSpace()); - if (Base->getType() != PointerTy) { + auto *ArrayPtrTy = PointerType::get( + SAI->getElementType(), Base->getType()->getPointerAddressSpace()); + + if (Base->getType() != ArrayPtrTy) Base = - Builder.CreateBitCast(Base, PointerTy, "polly.access.cast." + BaseName); - } + Builder.CreateBitCast(Base, ArrayPtrTy, "polly.array.cast." + BaseName); IndexOp = nullptr; for (unsigned u = 1, e = isl_ast_expr_get_op_n_arg(Expr); u < e; u++) { @@ -174,13 +175,29 @@ Access = Builder.CreateGEP(Base, IndexOp, "polly.access." + BaseName); isl_ast_expr_free(Expr); + + if (MA) { + auto *AccessPointer = + MemAccInst(*MA->getAccessInstruction()).getPointerOperand(); + if (Access->getType() != AccessPointer->getType()) + Access = Builder.CreatePointerCast(Access, AccessPointer->getType(), + "polly.access.cast." + BaseName); + } + return Access; } Value *IslExprBuilder::createOpAccess(isl_ast_expr *Expr) { + auto *BaseExpr = isl_ast_expr_get_op_arg(Expr, 0); + auto *MA = AccessId::getMA(isl_ast_expr_get_id(BaseExpr)); + assert((!MA || MA->isArrayKind()) && "Scalars have no address of"); + isl_ast_expr_free(BaseExpr); + Value *Addr = createAccessAddress(Expr); assert(Addr && "Could not create op access address"); - return Builder.CreateLoad(Addr, Addr->getName() + ".load"); + + unsigned Alignment = MA ? MA->getAlignment() : 0; + return Builder.CreateAlignedLoad(Addr, Alignment, Addr->getName() + ".load"); } Value *IslExprBuilder::createOpBin(__isl_take isl_ast_expr *Expr) { Index: lib/CodeGen/IslNodeBuilder.cpp =================================================================== --- lib/CodeGen/IslNodeBuilder.cpp +++ lib/CodeGen/IslNodeBuilder.cpp @@ -900,21 +900,8 @@ PWAccRel = isl_pw_multi_aff_gist_params(PWAccRel, S.getContext()); isl_ast_expr *Access = isl_ast_build_access_from_pw_multi_aff(Build, PWAccRel); - auto *Address = isl_ast_expr_address_of(Access); - auto *AddressValue = ExprBuilder.create(Address); - Value *PreloadVal; - - // Correct the type as the SAI might have a different type than the user - // expects, especially if the base pointer is a struct. - Type *Ty = AccInst->getType(); - - auto *Ptr = AddressValue; - auto Name = Ptr->getName(); - Ptr = Builder.CreatePointerCast(Ptr, Ty->getPointerTo(), Name + ".cast"); - PreloadVal = Builder.CreateLoad(Ptr, Name + ".load"); - if (LoadInst *PreloadInst = dyn_cast(PreloadVal)) - PreloadInst->setAlignment(dyn_cast(AccInst)->getAlignment()); - + Value *PreloadVal = ExprBuilder.create(Access); + assert(AccInst->getType() == PreloadVal->getType()); return PreloadVal; } Index: test/Isl/CodeGen/MemAccess/codegen_address_space.ll =================================================================== --- test/Isl/CodeGen/MemAccess/codegen_address_space.ll +++ test/Isl/CodeGen/MemAccess/codegen_address_space.ll @@ -39,6 +39,6 @@ ret i32 0 } -; CHECK: %polly.access.cast.A = bitcast [100 x i32] addrspace(5)* %A to i32 addrspace(5)* -; CHECK: %polly.access.A = getelementptr i32, i32 addrspace(5)* %polly.access.cast.A, i64 0 +; CHECK: %polly.array.cast.A = bitcast [100 x i32] addrspace(5)* %A to i32 addrspace(5)* +; CHECK: %polly.access.A = getelementptr i32, i32 addrspace(5)* %polly.array.cast.A, i64 0 ; CHECK: %tmp2_p_scalar_ = load i32, i32 addrspace(5)* %polly.access.A, align 4, !alias.scope !0, !noalias !2 Index: test/Isl/CodeGen/MemAccess/different_types.ll =================================================================== --- test/Isl/CodeGen/MemAccess/different_types.ll +++ test/Isl/CodeGen/MemAccess/different_types.ll @@ -9,11 +9,11 @@ ; A[i] += 10; ; } -; CHECK: %polly.access.cast.A14 = bitcast float* %A to i32* +; CHECK: %polly.array.cast.A14 = bitcast float* %A to i32* ; CHECK: %5 = sub nsw i64 99, %polly.indvar11 -; CHECK: %polly.access.A15 = getelementptr i32, i32* %polly.access.cast.A14, i64 %5 -; CHECK: %6 = bitcast i32* %polly.access.A15 to float* -; CHECK: %tmp14_p_scalar_ = load float, float* %6, align 4, !alias.scope !3, !noalias !4 +; CHECK: %polly.access.A15 = getelementptr i32, i32* %polly.array.cast.A14, i64 %5 +; CHECK: %polly.access.cast.A = bitcast i32* %polly.access.A15 to float* +; CHECK: %tmp14_p_scalar_ = load float, float* %polly.access.cast.A, align 4, !alias.scope !3, !noalias !4 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" Index: test/Isl/CodeGen/MemAccess/multiple_types.ll =================================================================== --- test/Isl/CodeGen/MemAccess/multiple_types.ll +++ test/Isl/CodeGen/MemAccess/multiple_types.ll @@ -13,19 +13,19 @@ ; 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 +; CHECK: %polly.access.cast.Short = bitcast i8* %polly.access.Short10 to i16* +; CHECK: %tmp5_p_scalar_ = load i16, i16* %polly.access.cast.Short ; 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 +; CHECK: %[[r:[0-9]*]] = mul nsw i64 8, %polly.indvar +; CHECK: %polly.access.Float11 = getelementptr i8, i8* %Float, i64 %[[r]] +; CHECK: %polly.access.cast.Float = bitcast i8* %polly.access.Float11 to float* +; CHECK: %tmp11_p_scalar_ = load float, float* %polly.access.cast.Float ; 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 +; CHECK: %polly.access.cast.Double = bitcast i8* %polly.access.Double13 to double* +; CHECK: %tmp17_p_scalar_ = load double, double* %polly.access.cast.Double target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" Index: test/Isl/CodeGen/aliasing_different_base_and_access_type.ll =================================================================== --- test/Isl/CodeGen/aliasing_different_base_and_access_type.ll +++ test/Isl/CodeGen/aliasing_different_base_and_access_type.ll @@ -2,8 +2,8 @@ ; ; We have to cast %B to "short *" before we create RTCs. ; -; CHECK: %polly.access.cast.B = bitcast i32* %B to i16* -; CHECK-NEXT: %polly.access.B = getelementptr i16, i16* %polly.access.cast.B, i64 1024 +; CHECK: %polly.array.cast.B = bitcast i32* %B to i16* +; CHECK-NEXT: %polly.access.B = getelementptr i16, i16* %polly.array.cast.B, i64 1024 ; ; We should never access %B as an i32 pointer: ; Index: test/Isl/CodeGen/aliasing_struct_element.ll =================================================================== --- test/Isl/CodeGen/aliasing_struct_element.ll +++ test/Isl/CodeGen/aliasing_struct_element.ll @@ -10,8 +10,8 @@ ; Verify that we do not use the offset 1423 into a non existent S array when we ; compute runtime alias checks but treat it as if it was a char array. ; -; CHECK: %polly.access.cast.S = bitcast %struct.st* %S to i8* -; CHECK: %polly.access.S = getelementptr i8, i8* %polly.access.cast.S, i64 1424 +; CHECK: %polly.array.cast.S = bitcast %struct.st* %S to i8* +; CHECK: %polly.access.S = getelementptr i8, i8* %polly.array.cast.S, i64 1424 ; ; struct st { ; int Dummy[100]; Index: test/Isl/CodeGen/invariant_load_different_sized_types.ll =================================================================== --- test/Isl/CodeGen/invariant_load_different_sized_types.ll +++ test/Isl/CodeGen/invariant_load_different_sized_types.ll @@ -4,8 +4,8 @@ target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" ; CHECK: polly.preload.begin: ; preds = %polly.split_new_and_old -; CHECK-NEXT: %polly.access.cast.tmp2 = bitcast %struct.hoge* %tmp2 to i32* -; CHECK-NEXT: %polly.access.tmp2 = getelementptr i32, i32* %polly.access.cast.tmp2, i64 1 +; CHECK-NEXT: %polly.array.cast.tmp2 = bitcast %struct.hoge* %tmp2 to i32* +; CHECK-NEXT: %polly.access.tmp2 = getelementptr i32, i32* %polly.array.cast.tmp2, i64 1 ; CHECK-NEXT: %polly.access.tmp2.load = load i32, i32* %polly.access.tmp2, align 1 ; CHECK-NEXT: store i32 %polly.access.tmp2.load, i32* %tmp.preload.s2a Index: test/Isl/CodeGen/multiple-types-invariant-load.ll =================================================================== --- test/Isl/CodeGen/multiple-types-invariant-load.ll +++ test/Isl/CodeGen/multiple-types-invariant-load.ll @@ -1,9 +1,14 @@ ; RUN: opt %loadPolly -polly-allow-differing-element-types -polly-codegen -S < %s | FileCheck %s -; CHECK: %polly.access.cast.global.load = bitcast %struct.hoge* %global.load to i32* -; CHECK: %polly.access.global.load = getelementptr i32, i32* %polly.access.cast.global.load, i64 0 +; CHECK: %polly.array.cast.global.load = bitcast %struct.hoge* %global.load to i32* +; CHECK: %polly.access.global.load = getelementptr i32, i32* %polly.array.cast.global.load, i64 0 ; CHECK: %polly.access.global.load.load = load i32, i32* %polly.access.global.load +; CHECK: %polly.array.cast.global.load1 = bitcast %struct.hoge* %global.load to i32* +; CHECK: %polly.access.global.load2 = getelementptr i32, i32* %polly.array.cast.global.load1, i64 2 +; CHECK: %polly.access.cast.global.load = bitcast i32* %polly.access.global.load2 to double* +; CHECK: %polly.access.cast.global.load.load = load double, double* %polly.access.cast.global.load + target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" Index: test/ScopInfo/invariant_load_access_classes_different_base_type_same_pointer.ll =================================================================== --- test/ScopInfo/invariant_load_access_classes_different_base_type_same_pointer.ll +++ test/ScopInfo/invariant_load_access_classes_different_base_type_same_pointer.ll @@ -32,10 +32,10 @@ ; CODEGEN: br label %polly.split_new_and_old ; ; CODEGEN: polly.preload.begin: -; CODEGEN-DAG: %U.load[[f:[.0-9]*]] = load float, float* bitcast (i32* @U to float*) -; CODEGEN-DAG: store float %U.load[[f]], float* %U.f.preload.s2a -; CODEGEN-DAG: %U.load[[i:[.0-9]*]] = load i32, i32* @U -; CODEGEN-DAG: store i32 %U.load[[i]], i32* %U.i.preload.s2a +; CODEGEN-DAG: %.load = load float, float* bitcast (i32* @U to float*) +; CODEGEN-DAG: store float %.load, float* %U.f.preload.s2a +; CODEGEN-DAG: %U.load = load i32, i32* @U +; CODEGEN-DAG: store i32 %U.load, i32* %U.i.preload.s2a ; ; CODEGEN: polly.merge_new_and_old: ; CODEGEN-NOT: merge = phi @@ -44,7 +44,7 @@ ; CODEGEN-NOT: final_reload ; ; CODEGEN: polly.stmt.for.body: -; CODEGEN: %p_add = add nsw i32 %U.load[[i]], %p_conv +; CODEGEN: %p_add = add nsw i32 %U.load, %p_conv ; target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" Index: test/ScopInfo/invariant_load_access_classes_different_base_type_same_pointer_escaping.ll =================================================================== --- test/ScopInfo/invariant_load_access_classes_different_base_type_same_pointer_escaping.ll +++ test/ScopInfo/invariant_load_access_classes_different_base_type_same_pointer_escaping.ll @@ -37,10 +37,10 @@ ; CODEGEN: br label %polly.split_new_and_old ; ; CODEGEN: polly.preload.begin: -; CODEGEN-DAG: %U.load[[f:[.0-9]*]] = load float, float* bitcast (i32* @U to float*) -; CODEGEN-DAG: store float %U.load[[f]], float* %U.f.preload.s2a -; CODEGEN-DAG: %U.load[[i:[.0-9]*]] = load i32, i32* @U -; CODEGEN-DAG: store i32 %U.load[[i]], i32* %U.i.preload.s2a +; CODEGEN-DAG: %.load = load float, float* bitcast (i32* @U to float*) +; CODEGEN-DAG: store float %.load, float* %U.f.preload.s2a +; CODEGEN-DAG: %U.load = load i32, i32* @U +; CODEGEN-DAG: store i32 %U.load, i32* %U.i.preload.s2a ; ; CODEGEN: polly.merge_new_and_old: ; CODEGEN-DAG: %U.f.merge = phi float [ %U.f.final_reload, %polly.exiting ], [ %U.f, %do.cond ] @@ -51,7 +51,7 @@ ; CODEGEN-DAG: %U.i.final_reload = load i32, i32* %U.i.preload.s2a ; ; CODEGEN: polly.stmt.do.body: -; CODEGEN: %p_add = add nsw i32 %U.load[[i]], %p_conv +; CODEGEN: %p_add = add nsw i32 %U.load, %p_conv ; target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" Index: test/ScopInfo/multiple-types-inv-load.ll =================================================================== --- /dev/null +++ test/ScopInfo/multiple-types-inv-load.ll @@ -0,0 +1,93 @@ +; RUN: opt %loadPolly -polly-allow-differing-element-types -polly-scops -analyze < %s | FileCheck %s +; RUN: opt %loadPolly -polly-allow-differing-element-types -polly-codegen -S < %s | FileCheck --check-prefix=IR %s +; +; // Check that accessing one array with different types works, even though +; // some of the accesses will be hoisted (they are invariant) and generated +; // (not copied) prior to the SCoP. +; void multiple_types(char *Short, char *Float, char *Double) { +; for (long i = 20; i < 100; i++) { +; Short[i] = *(short *)&Short[2]; +; Float[i] = *(float *)&Float[4]; +; Double[i] = *(double *)&Double[8]; +; } +; } +; +; CHECK: Invariant Accesses: { +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: { Stmt_bb2[i0] -> MemRef_Short[o0] : 2 <= o0 <= 3 }; +; CHECK-NEXT: Execution Context: { : } +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: { Stmt_bb2[i0] -> MemRef_Float[o0] : 4 <= o0 <= 7 }; +; CHECK-NEXT: Execution Context: { : } +; CHECK-NEXT: ReadAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: { Stmt_bb2[i0] -> MemRef_Double[o0] : 8 <= o0 <= 15 }; +; CHECK-NEXT: Execution Context: { : } +; CHECK-NEXT: } +; +; CHECK: Statements { +; CHECK-NEXT: Stmt_bb2 +; CHECK-NEXT: Domain := +; CHECK-NEXT: { Stmt_bb2[i0] : 0 <= i0 <= 79 }; +; CHECK-NEXT: Schedule := +; CHECK-NEXT: { Stmt_bb2[i0] -> [i0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: { Stmt_bb2[i0] -> MemRef_Short[20 + i0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: { Stmt_bb2[i0] -> MemRef_Float[20 + i0] }; +; CHECK-NEXT: MustWriteAccess := [Reduction Type: NONE] [Scalar: 0] +; CHECK-NEXT: { Stmt_bb2[i0] -> MemRef_Double[20 + i0] }; +; CHECK-NEXT: } +; +; IR: polly.preload.begin: +; IR-NEXT: %polly.access.Short = getelementptr i8, i8* %Short, i64 2 +; IR-NEXT: %polly.access.cast.Short = bitcast i8* %polly.access.Short to i16* +; IR-NEXT: %polly.access.cast.Short.load = load i16, i16* %polly.access.cast.Short, align 2 +; IR-NEXT: store i16 %polly.access.cast.Short.load +; IR-NEXT: %polly.access.Float = getelementptr i8, i8* %Float, i64 4 +; IR-NEXT: %polly.access.cast.Float = bitcast i8* %polly.access.Float to float* +; IR-NEXT: %polly.access.cast.Float.load = load float, float* %polly.access.cast.Float, align 4 +; IR-NEXT: store float %polly.access.cast.Float.load +; IR-NEXT: %polly.access.Double = getelementptr i8, i8* %Double, i64 8 +; IR-NEXT: %polly.access.cast.Double = bitcast i8* %polly.access.Double to double* +; IR-NEXT: %polly.access.cast.Double.load = load double, double* %polly.access.cast.Double, align 8 +; IR-NEXT: store double %polly.access.cast.Double.load +; +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 [ 20, %bb ], [ %tmp21, %bb20 ] + %exitcond = icmp ne i64 %i.0, 100 + br i1 %exitcond, label %bb2, label %bb22 + +bb2: ; preds = %bb1 + %tmp3 = getelementptr inbounds i8, i8* %Short, i64 2 + %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 + %tmp9 = getelementptr inbounds i8, i8* %Float, i64 4 + %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 + %tmp15 = getelementptr inbounds i8, i8* %Double, i64 8 + %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 +}