blob: 03ad24a6f757ac657a3042fe06e36797ff871969 [file] [log] [blame]
/*
* Copyright 2015, The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bcc/Assert.h"
#include "bcc/Renderscript/RSTransforms.h"
#include <llvm/Pass.h>
#include <llvm/IR/DataLayout.h>
#include <llvm/IR/DIBuilder.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/Function.h>
#include <llvm/IR/InstIterator.h>
#include <llvm/IR/Instructions.h>
#include <llvm/IR/MDBuilder.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Type.h>
#include <llvm/Transforms/Utils/BasicBlockUtils.h>
namespace {
const char DEBUG_SOURCE_PATH[] = "/opt/renderscriptdebugger/1";
const char DEBUG_GENERATED_FILE[] = "generated.rs";
/*
* LLVM pass to attach debug information to the bits of code
* generated by the compiler.
*/
class RSAddDebugInfoPass : public llvm::ModulePass {
public:
// Pass ID
static char ID;
RSAddDebugInfoPass() : ModulePass(ID) {
}
virtual bool runOnModule(llvm::Module &Module) {
// Set up the debug info builder.
llvm::DIBuilder DebugInfo(Module);
DebugInfo.createCompileUnit(llvm::dwarf::DW_LANG_C99,
DEBUG_GENERATED_FILE, DEBUG_SOURCE_PATH,
"RS", false, "", 0);
// Attach DI metadata to each generated function.
for (llvm::Function &Func : Module)
if (Func.getName().endswith(".expand"))
attachDebugInfo(DebugInfo, Func);
DebugInfo.finalize();
return true;
}
private:
/// @brief Add debug information to a generated function.
///
/// This function is used to attach source file and line information
/// to the generated function code.
void attachDebugInfo(llvm::DIBuilder &DebugInfo, llvm::Function &Func) {
llvm::DIFile *sourceFileName =
DebugInfo.createFile(DEBUG_GENERATED_FILE, DEBUG_SOURCE_PATH);
// Fabricated function type
llvm::MDTuple *nullMD = llvm::MDTuple::get(Func.getParent()->getContext(),
{ DebugInfo.createUnspecifiedType("void") });
// Create function-level debug metadata.
llvm::DIScope *GeneratedScope = DebugInfo.createFunction(
sourceFileName, // scope
Func.getName(), Func.getName(),
sourceFileName, 1,
DebugInfo.createSubroutineType(sourceFileName, nullMD),
false, true, 1, 0, false, &Func
);
// Attach location inforamtion to each instruction in the function
for (llvm::inst_iterator Inst = llvm::inst_begin(Func),
InstEnd = llvm::inst_end(Func);
Inst != InstEnd;
++Inst) {
Inst->setDebugLoc(llvm::DebugLoc::get(1, 1, GeneratedScope));
}
}
}; // end class RSAddDebugInfoPass
char RSAddDebugInfoPass::ID = 0;
static llvm::RegisterPass<RSAddDebugInfoPass> X("addrsdi", "Add RS DebugInfo Pass");
} // end anonymous namespace
namespace bcc {
llvm::ModulePass * createRSAddDebugInfoPass() {
return new RSAddDebugInfoPass();
}
} // end namespace bcc