Index: polly/trunk/include/polly/LinkAllPasses.h =================================================================== --- polly/trunk/include/polly/LinkAllPasses.h +++ polly/trunk/include/polly/LinkAllPasses.h @@ -46,6 +46,7 @@ llvm::Pass *createScopDetectionWrapperPassPass(); llvm::Pass *createScopInfoRegionPassPass(); llvm::Pass *createScopInfoWrapperPassPass(); +llvm::Pass *createRewriteByrefParamsPass(); llvm::Pass *createIslAstInfoWrapperPassPass(); llvm::Pass *createCodeGenerationPass(); #ifdef GPU_CODEGEN @@ -112,6 +113,7 @@ void initializeJSONImporterPass(llvm::PassRegistry &); void initializeIslAstInfoWrapperPassPass(llvm::PassRegistry &); void initializeCodeGenerationPass(llvm::PassRegistry &); +void initializeRewriteByrefParamsPass(llvm::PassRegistry &); #ifdef GPU_CODEGEN void initializePPCGCodeGenerationPass(llvm::PassRegistry &); void initializeManagedMemoryRewritePassPass(llvm::PassRegistry &); Index: polly/trunk/lib/CMakeLists.txt =================================================================== --- polly/trunk/lib/CMakeLists.txt +++ polly/trunk/lib/CMakeLists.txt @@ -64,6 +64,7 @@ Transform/ZoneAlgo.cpp Transform/Simplify.cpp Transform/MaximalStaticExpansion.cpp + Transform/RewriteByReferenceParameters.cpp ${POLLY_HEADER_FILES} ) set_target_properties(PollyCore PROPERTIES FOLDER "Polly") Index: polly/trunk/lib/Support/RegisterPasses.cpp =================================================================== --- polly/trunk/lib/Support/RegisterPasses.cpp +++ polly/trunk/lib/Support/RegisterPasses.cpp @@ -266,6 +266,7 @@ initializeScopDetectionWrapperPassPass(Registry); initializeScopInfoRegionPassPass(Registry); initializeScopInfoWrapperPassPass(Registry); + initializeRewriteByrefParamsPass(Registry); initializeCodegenCleanupPass(Registry); initializeFlattenSchedulePass(Registry); initializeForwardOpTreePass(Registry); Index: polly/trunk/lib/Transform/Canonicalization.cpp =================================================================== --- polly/trunk/lib/Transform/Canonicalization.cpp +++ polly/trunk/lib/Transform/Canonicalization.cpp @@ -28,6 +28,7 @@ cl::init(false), cl::ZeroOrMore, cl::cat(PollyCategory)); void polly::registerCanonicalicationPasses(llvm::legacy::PassManagerBase &PM) { + PM.add(polly::createRewriteByrefParamsPass()); PM.add(llvm::createPromoteMemoryToRegisterPass()); PM.add(llvm::createInstructionCombiningPass()); PM.add(llvm::createCFGSimplificationPass()); Index: polly/trunk/lib/Transform/RewriteByReferenceParameters.cpp =================================================================== --- polly/trunk/lib/Transform/RewriteByReferenceParameters.cpp +++ polly/trunk/lib/Transform/RewriteByReferenceParameters.cpp @@ -0,0 +1,99 @@ +//===------ RewriteByReferenceParameters.cpp --------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This pass introduces separate 'alloca' instructions for read-only +// by-reference function parameters to indicate that these paramters are +// read-only. After this transformation -mem2reg has more freedom to promote +// variables to registers, which allows SCEV to work in more cases. +// +//===----------------------------------------------------------------------===// + +#include "polly/LinkAllPasses.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/PassManager.h" + +#define DEBUG_TYPE "polly-rewrite-byref-params" + +using namespace llvm; + +namespace { + +class RewriteByrefParams : public FunctionPass { +private: + RewriteByrefParams(const RewriteByrefParams &) = delete; + const RewriteByrefParams &operator=(const RewriteByrefParams &) = delete; + +public: + static char ID; + explicit RewriteByrefParams() : FunctionPass(ID) {} + + virtual void getAnalysisUsage(AnalysisUsage &AU) const override {} + + void tryRewriteInstruction(Instruction &Inst) { + BasicBlock *Entry = &Inst.getParent()->getParent()->getEntryBlock(); + + auto *Call = dyn_cast(&Inst); + + if (!Call) + return; + + llvm::Function *F = Call->getCalledFunction(); + + if (!F) + return; + + // We currently match for a very specific function. In case this proves + // useful, we can make this code dependent on readonly metadata. + if (!F->hasName() || F->getName() != "_gfortran_transfer_integer_write") + return; + + auto *BitCast = dyn_cast(Call->getOperand(1)); + + if (!BitCast) + return; + + auto *Alloca = dyn_cast(BitCast->getOperand(0)); + + if (!Alloca) + return; + + std::string InstName = Alloca->getName(); + + auto NewAlloca = + new AllocaInst(Alloca->getType()->getElementType(), 0, + "polly_byref_alloca_" + InstName, &*Entry->begin()); + + auto *LoadedVal = + new LoadInst(Alloca, "polly_byref_load_" + InstName, &Inst); + + new StoreInst(LoadedVal, NewAlloca, &Inst); + auto *NewBitCast = new BitCastInst(NewAlloca, BitCast->getType(), + "polly_byref_cast_" + InstName, &Inst); + Call->setOperand(1, NewBitCast); + } + + virtual bool runOnFunction(Function &F) override { + for (BasicBlock &BB : F) + for (Instruction &Inst : BB) + tryRewriteInstruction(Inst); + + return true; + } +}; + +char RewriteByrefParams::ID; +} // anonymous namespace + +Pass *polly::createRewriteByrefParamsPass() { return new RewriteByrefParams(); } + +INITIALIZE_PASS_BEGIN(RewriteByrefParams, "polly-rewrite-byref-params", + "Polly - Rewrite by reference parameters", false, false) +INITIALIZE_PASS_END(RewriteByrefParams, "polly-rewrite-byref-params", + "Polly - Rewrite by reference parameters", false, false) Index: polly/trunk/test/RewriteByReferenceParameters/fortran_io.ll =================================================================== --- polly/trunk/test/RewriteByReferenceParameters/fortran_io.ll +++ polly/trunk/test/RewriteByReferenceParameters/fortran_io.ll @@ -0,0 +1,40 @@ +; RUN: opt %loadPolly -polly-rewrite-byref-params -S < %s \ +; RUN: | FileCheck %s + + +; Verify that we rewrite the read-only by-reference into a separate alloca slot. +; This is useful in case %j3 is an induction variable, which should be promoted +; by -mem2reg into a register. + +; CHECK: define void @foo(%struct.__st_parameter_dt* %p) { +; CHECK-NEXT: entry: +; CHECK-NEXT: %polly_byref_alloca_j3 = alloca i32 +; CHECK-NEXT: %j3 = alloca i32, align 4 +; CHECK-NEXT: %tmp = bitcast i32* %j3 to i8* +; CHECK-NEXT: br label %bb + +; CHECK: bb: ; preds = %entry +; CHECK-NEXT: %polly_byref_load_j3 = load i32, i32* %j3 +; CHECK-NEXT: store i32 %polly_byref_load_j3, i32* %polly_byref_alloca_j3 +; CHECK-NEXT: %polly_byref_cast_j3 = bitcast i32* %polly_byref_alloca_j3 to i8* +; CHECK-NEXT: call void @_gfortran_transfer_integer_write(%struct.__st_parameter_dt* %p, i8* %polly_byref_cast_j3, i32 4) +; CHECK-NEXT: ret void +; CHECK-NEXT: } + +target datalayout = "e-p:64:64:64-S128-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f16:16:16-f32:32:32-f64:64:64-f128:128:128-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64" +target triple = "x86_64-unknown-linux-gnu" + +%struct.__st_parameter_dt = type { } + +declare void @_gfortran_transfer_integer_write(%struct.__st_parameter_dt*, i8*, i32) + +define void @foo(%struct.__st_parameter_dt* %p) { +entry: + %j3 = alloca i32, align 4 + %tmp = bitcast i32* %j3 to i8* + br label %bb + +bb: + call void @_gfortran_transfer_integer_write(%struct.__st_parameter_dt* %p, i8* %tmp, i32 4) + ret void +}