Merge "Add option to generate reflected C++ code."
diff --git a/RSCCOptions.td b/RSCCOptions.td
index be992f5..ebd7f36 100644
--- a/RSCCOptions.td
+++ b/RSCCOptions.td
@@ -60,6 +60,12 @@
HelpText<"Build ASTs then convert to LLVM, but emit nothing">;
}
+def emit_g : Flag<"-g">,
+ HelpText<"Emit LLVM Debug Metadata">;
+
+def optimization_level : Separate<"-O">, MetaVarName<"<optimization-level>">,
+ HelpText<"<optimization-level> can be one of '0' or '3' (default)">;
+
def allow_rs_prefix : Flag<"-allow-rs-prefix">,
HelpText<"Allow user-defined function prefixed with 'rs'">;
diff --git a/lit-tests/README b/lit-tests/README
new file mode 100644
index 0000000..78fea67
--- /dev/null
+++ b/lit-tests/README
@@ -0,0 +1,42 @@
+
+Summary
+=======
+This directory contains tests for Slang that use the 'llvm-lit' testing tool.
+Each testcase is a separate .rs file, and comments inside the testcase are
+used to verify certain strings are present in the output bitcode files.
+
+Prerequisites
+=============
+To run the tests, you must have the android build environment variables
+set (i.e. source build/envsetup.sh; lunch). You must also have on your path:
+- Android version of llvm-lit (currently in libbcc/tests/debuginfo)
+- FileCheck (utility from llvm)
+- llvm-rs-cc (slang frontend compiler)
+
+If you are unable to run the tests, try using the "--debug" option to llvm-lit.
+
+When debugging failures, the "-v" option will print to stdout the details of
+the failure. Note that tests marked as "Expected Fail" (XFAIL) will not print
+failure information, even with -v.
+
+Customizing
+===========
+The tools lit and FileCheck are fairly flexible, and could be used to validate
+more than just emitted bitcode. For example, with some changes to the testcases
+and the helper shell-script rs-filecheck-wrapper.sh, it should be possible to
+write tests that verify the emitted Java code.
+
+Running
+=======
+To execute all the tests from this directory, use the Android llvm-lit tool
+from libbcc:
+$ ../../libbcc/tests/debuginfo/llvm-lit .
+
+The tool can be run from any directory.
+-j controls the number of parallel test executions
+-v enables additional verbosity (useful when examining unexpected failures)
+
+Adding new tests
+================
+To add new tests, just add .rs files to a test directory with similar
+RUN/CHECK directives in comments as the existing tests.
diff --git a/lit-tests/debug_disabled.rs b/lit-tests/debug_disabled.rs
new file mode 100644
index 0000000..4485697
--- /dev/null
+++ b/lit-tests/debug_disabled.rs
@@ -0,0 +1,10 @@
+// RUN: %Slang %s
+// RUN: %rs-filecheck-wrapper %s
+// CHECK-NOT: DW_TAG_subprogram
+
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+void root(const int *ain, int *aout, const void *usrData,
+ uint32_t x, uint32_t y) {
+}
diff --git a/lit-tests/debug_enabled.rs b/lit-tests/debug_enabled.rs
new file mode 100644
index 0000000..4632744
--- /dev/null
+++ b/lit-tests/debug_enabled.rs
@@ -0,0 +1,10 @@
+// RUN: %Slang -g %s
+// RUN: %rs-filecheck-wrapper %s
+// CHECK: DW_TAG_subprogram
+
+#pragma version(1)
+#pragma rs java_package_name(foo)
+
+void root(const int *ain, int *aout, const void *usrData,
+ uint32_t x, uint32_t y) {
+}
diff --git a/lit-tests/lit.cfg b/lit-tests/lit.cfg
new file mode 100644
index 0000000..1fb7692
--- /dev/null
+++ b/lit-tests/lit.cfg
@@ -0,0 +1,66 @@
+# -*- Python -*-
+
+# Configuration file for the 'lit' test runner.
+
+# name: The name of this test suite.
+config.name = 'slang_lit_tests'
+
+# suffixes: A list of file extensions to treat as test files.
+config.suffixes = ['.rs']
+
+# testFormat: The test format to use to interpret tests.
+config.test_format = lit.formats.ShTest()
+
+# Get the base build directory for the android source tree from environment.
+config.base_path = os.getenv('ANDROID_BUILD_TOP')
+
+# test_source_root: The path where tests are located (default is the test suite
+# root).
+config.test_source_root = None
+
+# test_exec_root: The path where tests are located (default is the test suite
+# root).
+config.test_exec_root = os.path.join(config.base_path, 'out', 'tests', 'slang', 'lit-tests')
+
+# target_triple: Used by ShTest and TclTest formats for XFAIL checks.
+config.target_triple = 'slang'
+
+def inferTool(binary_name, env_var, PATH):
+ # Determine which tool to use.
+ tool = os.getenv(env_var)
+
+ # If the user set the overriding environment variable, use it
+ if tool and os.path.isfile(tool):
+ return tool
+
+ # Otherwise look in the path.
+ tool = lit.util.which(binary_name, PATH)
+
+ if not tool:
+ lit.fatal("couldn't find " + binary_name + " program in " + PATH + " , try setting "
+ + env_var + " in your environment")
+
+ return os.path.abspath(tool)
+
+config.slang = inferTool('llvm-rs-cc', 'SLANG', os.path.join(config.base_path, 'out', 'host', 'linux-x86', 'bin')).replace('\\', '/')
+
+config.filecheck = inferTool('FileCheck', 'FILECHECK', config.environment['PATH'])
+config.rs_filecheck_wrapper = inferTool('rs-filecheck-wrapper.sh', 'RS_FILECHECK_WRAPPER', os.path.join(config.base_path, 'frameworks', 'compile', 'slang', 'lit-tests'))
+
+# TODO: fix up for other SDKs. Maybe use lit parameter?
+config.slang_includes = "-I " + os.path.join(config.base_path, 'prebuilt', 'sdk', '14', 'renderscript', 'include') + " " \
+ + "-I " + os.path.join(config.base_path, 'prebuilt', 'sdk', '14', 'renderscript', 'clang-include')
+
+config.slang_options = "-emit-llvm -o " + config.test_exec_root \
+ + " -output-dep-dir " + config.test_exec_root \
+ + " -java-reflection-path-base " + config.test_exec_root
+
+if not lit.quiet:
+ lit.note('using slang: %r' % config.slang)
+ lit.note('using FileCheck: %r' % config.filecheck)
+ lit.note('using rs-filecheck-wrapper.sh: %r' % config.rs_filecheck_wrapper)
+ lit.note('using output directory: %r' % config.test_exec_root)
+
+# Tools configuration substitutions
+config.substitutions.append( ('%Slang', ' ' + config.slang + ' ' + config.slang_includes + ' ' + config.slang_options ) )
+config.substitutions.append( ('%rs-filecheck-wrapper', ' ' + config.rs_filecheck_wrapper + ' ' + config.test_exec_root + ' ' + config.filecheck + ' ') )
diff --git a/lit-tests/locals_opt_0.rs b/lit-tests/locals_opt_0.rs
new file mode 100644
index 0000000..1c1f7de
--- /dev/null
+++ b/lit-tests/locals_opt_0.rs
@@ -0,0 +1,45 @@
+// RUN: %Slang -O 0 %s
+// RUN: %rs-filecheck-wrapper %s
+// CHECK: define internal i32 @main(
+// CHECK: %f = alloca float,
+// CHECK: %pf = alloca float*,
+// CHECK: %ppn = alloca i32**,
+
+struct float_struct {
+ float f;
+ float f2[2];
+} compound_float;
+
+static
+int main(int argc, char* argv[])
+{
+ float f = 0.f;
+ float *pf = &f;
+
+ double d[2][2] = {{0, 1}, {2, 3.0}};
+ struct float_struct s;
+
+ unsigned short us = -1;
+ const unsigned long l = (unsigned long) -1.0e8f;
+
+ {
+ int** ppn = 0;
+ if (ppn) {
+ return -1;
+ }
+ }
+
+ s.f = 10e-4f;
+ s.f2[0] = 1e4f;
+ s.f2[1] = 100.5f;
+
+ double result = pf[0] * d[1][1] * s.f * us * l;
+ return (result == 0 ? 0 : -1);
+}
+
+void the_main() {
+ main(0, 0);
+}
+
+#pragma version(1)
+#pragma rs java_package_name(foo)
diff --git a/lit-tests/locals_opt_3.rs b/lit-tests/locals_opt_3.rs
new file mode 100644
index 0000000..e90a538
--- /dev/null
+++ b/lit-tests/locals_opt_3.rs
@@ -0,0 +1,45 @@
+// RUN: %Slang -O 3 %s
+// RUN: %rs-filecheck-wrapper %s
+// CHECK-NOT: define internal i32 @main(
+// CHECK-NOT: %f = alloca float,
+// CHECK-NOT: %pf = alloca float*,
+// CHECK-NOT: %ppn = alloca i32**,
+
+struct float_struct {
+ float f;
+ float f2[2];
+} compound_float;
+
+static
+int main(int argc, char* argv[])
+{
+ float f = 0.f;
+ float *pf = &f;
+
+ double d[2][2] = {{0, 1}, {2, 3.0}};
+ struct float_struct s;
+
+ unsigned short us = -1;
+ const unsigned long l = (unsigned long) -1.0e8f;
+
+ {
+ int** ppn = 0;
+ if (ppn) {
+ return -1;
+ }
+ }
+
+ s.f = 10e-4f;
+ s.f2[0] = 1e4f;
+ s.f2[1] = 100.5f;
+
+ double result = pf[0] * d[1][1] * s.f * us * l;
+ return (result == 0 ? 0 : -1);
+}
+
+void the_main() {
+ main(0, 0);
+}
+
+#pragma version(1)
+#pragma rs java_package_name(foo)
diff --git a/lit-tests/locals_opt_default.rs b/lit-tests/locals_opt_default.rs
new file mode 100644
index 0000000..f491956
--- /dev/null
+++ b/lit-tests/locals_opt_default.rs
@@ -0,0 +1,48 @@
+// RUN: %Slang %s
+// RUN: %rs-filecheck-wrapper %s
+// CHECK-NOT: define internal i32 @main(
+// CHECK-NOT: %f = alloca float,
+// CHECK-NOT: %pf = alloca float*,
+// CHECK-NOT: %ppn = alloca i32**,
+
+// This test case should behave identically to locals_opt_3.rs.
+
+struct float_struct {
+ float f;
+ float f2[2];
+} compound_float;
+
+
+static
+int main(int argc, char* argv[])
+{
+ float f = 0.f;
+ float *pf = &f;
+
+ double d[2][2] = {{0, 1}, {2, 3.0}};
+ struct float_struct s;
+
+ unsigned short us = -1;
+ const unsigned long l = (unsigned long) -1.0e8f;
+
+ {
+ int** ppn = 0;
+ if (ppn) {
+ return -1;
+ }
+ }
+
+ s.f = 10e-4f;
+ s.f2[0] = 1e4f;
+ s.f2[1] = 100.5f;
+
+ double result = pf[0] * d[1][1] * s.f * us * l;
+ return (result == 0 ? 0 : -1);
+}
+
+void the_main() {
+ main(0, 0);
+}
+
+#pragma version(1)
+#pragma rs java_package_name(foo)
diff --git a/lit-tests/rs-filecheck-wrapper.sh b/lit-tests/rs-filecheck-wrapper.sh
new file mode 100755
index 0000000..816c80a
--- /dev/null
+++ b/lit-tests/rs-filecheck-wrapper.sh
@@ -0,0 +1,12 @@
+#!/bin/bash -e
+
+# RS Invocation script to FileCheck
+# Usage: rs-filecheck-wrapper.sh <output-directory> <path-to-FileCheck> <source>
+
+OUTDIR=$1
+FILECHECK=$2
+SOURCEFILE=$3
+
+FILECHECK_INPUTFILE=`basename $SOURCEFILE | sed 's/\.rs\$/.ll/'`
+
+$FILECHECK -input-file $OUTDIR/$FILECHECK_INPUTFILE $SOURCEFILE
diff --git a/llvm-rs-cc.cpp b/llvm-rs-cc.cpp
index d25d6e6..2cd7bb0 100644
--- a/llvm-rs-cc.cpp
+++ b/llvm-rs-cc.cpp
@@ -41,6 +41,7 @@
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/system_error.h"
+#include "llvm/Target/TargetMachine.h"
#include "slang.h"
#include "slang_assert.h"
@@ -142,6 +143,12 @@
unsigned int mTargetAPI;
+ // Enable emission of debugging symbols
+ unsigned mDebugEmission : 1;
+
+ // The optimization level used in CodeGen, and encoded in emitted bitcode
+ llvm::CodeGenOpt::Level mOptimizationLevel;
+
RSCCOptions() {
mOutputType = slang::Slang::OT_Bitcode;
// Triple/CPU/Features must be hard-coded to our chosen portable ABI.
@@ -154,6 +161,8 @@
mShowHelp = 0;
mShowVersion = 0;
mTargetAPI = RS_VERSION;
+ mDebugEmission = 0;
+ mOptimizationLevel = llvm::CodeGenOpt::Aggressive;
}
};
@@ -275,6 +284,14 @@
Opts.mShowHelp = Args->hasArg(OPT_help);
Opts.mShowVersion = Args->hasArg(OPT_version);
+ Opts.mDebugEmission = Args->hasArg(OPT_emit_g);
+
+ size_t OptLevel = Args->getLastArgIntValue(OPT_optimization_level,
+ 3,
+ DiagEngine);
+
+ Opts.mOptimizationLevel = OptLevel == 0 ? llvm::CodeGenOpt::None
+ : llvm::CodeGenOpt::Aggressive;
Opts.mTargetAPI = Args->getLastArgIntValue(OPT_target_api,
RS_VERSION,
@@ -458,6 +475,8 @@
Opts.mAllowRSPrefix,
Opts.mOutputDep,
Opts.mTargetAPI,
+ Opts.mDebugEmission,
+ Opts.mOptimizationLevel,
Opts.mJavaReflectionPathBase,
Opts.mJavaReflectionPackageName);
diff --git a/slang.cpp b/slang.cpp
index ff03836..1c33f4d 100644
--- a/slang.cpp
+++ b/slang.cpp
@@ -157,7 +157,7 @@
LangOpts.C99 = 1;
LangOpts.CharIsSigned = 1; // Signed char is our default.
- CodeGenOpts.OptimizationLevel = 3; /* -O3 */
+ CodeGenOpts.OptimizationLevel = 3;
GlobalInitialized = true;
}
@@ -450,6 +450,14 @@
return mDiagEngine->hasErrorOccurred() ? 1 : 0;
}
+void Slang::setDebugMetadataEmission(bool EmitDebug) {
+ CodeGenOpts.DebugInfo = EmitDebug;
+}
+
+void Slang::setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel) {
+ CodeGenOpts.OptimizationLevel = OptimizationLevel;
+}
+
void Slang::reset() {
llvm::errs() << mDiagClient->str();
mDiagEngine->Reset();
diff --git a/slang.h b/slang.h
index 6b162f4..16f851e 100644
--- a/slang.h
+++ b/slang.h
@@ -28,6 +28,8 @@
#include "llvm/ADT/OwningPtr.h"
#include "llvm/ADT/StringRef.h"
+#include "llvm/Target/TargetMachine.h"
+
#include "slang_diagnostic_buffer.h"
#include "slang_pragma_recorder.h"
@@ -216,6 +218,10 @@
char const *getErrorMessage() { return mDiagClient->str().c_str(); }
+ void setDebugMetadataEmission(bool EmitDebug);
+
+ void setOptimizationLevel(llvm::CodeGenOpt::Level OptimizationLevel);
+
// Reset the slang compiler state such that it can be reused to compile
// another file
virtual void reset();
diff --git a/slang_backend.cpp b/slang_backend.cpp
index 72cd47c..9281f39 100644
--- a/slang_backend.cpp
+++ b/slang_backend.cpp
@@ -208,7 +208,6 @@
llvm::raw_ostream *OS,
Slang::OutputType OT)
: ASTConsumer(),
- mCodeGenOpts(CodeGenOpts),
mTargetOpts(TargetOpts),
mpModule(NULL),
mpOS(OS),
@@ -219,6 +218,7 @@
mCodeGenPasses(NULL),
mLLVMContext(llvm::getGlobalContext()),
mDiagEngine(*DiagEngine),
+ mCodeGenOpts(CodeGenOpts),
mPragmas(Pragmas) {
FormattedOutStream.setStream(*mpOS,
llvm::formatted_raw_ostream::PRESERVE_STREAM);
diff --git a/slang_backend.h b/slang_backend.h
index 71cd1c7..69721fe 100644
--- a/slang_backend.h
+++ b/slang_backend.h
@@ -48,7 +48,6 @@
class Backend : public clang::ASTConsumer {
private:
- const clang::CodeGenOptions &mCodeGenOpts;
const clang::TargetOptions &mTargetOpts;
llvm::Module *mpModule;
@@ -80,6 +79,7 @@
protected:
llvm::LLVMContext &mLLVMContext;
clang::DiagnosticsEngine &mDiagEngine;
+ const clang::CodeGenOptions &mCodeGenOpts;
PragmaList *mPragmas;
diff --git a/slang_rs.cpp b/slang_rs.cpp
index 22e694a..13413c0 100644
--- a/slang_rs.cpp
+++ b/slang_rs.cpp
@@ -261,7 +261,8 @@
const std::vector<std::string> &AdditionalDepTargets,
Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage,
bool AllowRSPrefix, bool OutputDep,
- unsigned int TargetAPI,
+ unsigned int TargetAPI, bool EmitDebug,
+ llvm::CodeGenOpt::Level OptimizationLevel,
const std::string &JavaReflectionPathBase,
const std::string &JavaReflectionPackageName) {
if (IOFiles.empty())
@@ -284,6 +285,10 @@
setAdditionalDepTargets(AdditionalDepTargets);
}
+ setDebugMetadataEmission(EmitDebug);
+
+ setOptimizationLevel(OptimizationLevel);
+
mAllowRSPrefix = AllowRSPrefix;
mTargetAPI = TargetAPI;
diff --git a/slang_rs.h b/slang_rs.h
index 09ec651..b2ef41d 100644
--- a/slang_rs.h
+++ b/slang_rs.h
@@ -120,6 +120,11 @@
//
// @JavaReflectionPathBase - The path base for storing reflection files.
//
+ // @EmitDebug - true to allow debug metadata emission
+ //
+ // @OptimizationLevel - code generation optimization level: None is recommended for
+ // interactive debugging. The default is Aggresive.
+ //
// @JavaReflectionPackageName - The package name given by user in command
// line. This may override the package name
// specified in the .rs using #pragma.
@@ -130,7 +135,8 @@
const std::vector<std::string> &AdditionalDepTargets,
Slang::OutputType OutputType, BitCodeStorageType BitcodeStorage,
bool AllowRSPrefix, bool OutputDep,
- unsigned int TargetAPI,
+ unsigned int TargetAPI, bool EmitDebug,
+ llvm::CodeGenOpt::Level OptimizationLevel,
const std::string &JavaReflectionPathBase,
const std::string &JavaReflectionPackageName);
diff --git a/slang_rs_backend.cpp b/slang_rs_backend.cpp
index 20b9395..ba9c26b 100644
--- a/slang_rs_backend.cpp
+++ b/slang_rs_backend.cpp
@@ -19,6 +19,8 @@
#include <string>
#include <vector>
+#include "clang/Frontend/CodeGenOptions.h"
+
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/StringExtras.h"
@@ -29,6 +31,7 @@
#include "llvm/Metadata.h"
#include "llvm/Module.h"
+#include "llvm/Support/DebugLoc.h"
#include "llvm/Support/IRBuilder.h"
#include "slang_assert.h"
@@ -61,6 +64,7 @@
mExportForEachSignatureMetadata(NULL),
mExportTypeMetadata(NULL),
mRSObjectSlotsMetadata(NULL),
+ mRSOptimizationMetadata(NULL),
mRefCount(mContext->getASTContext()) {
}
@@ -194,6 +198,16 @@
return;
}
+ // Write optimization level
+ llvm::SmallVector<llvm::Value*, 1> OptimizationOption;
+ OptimizationOption.push_back(llvm::ConstantInt::get(
+ mLLVMContext, llvm::APInt(32, mCodeGenOpts.OptimizationLevel)));
+
+ if (mRSOptimizationMetadata == NULL)
+ mRSOptimizationMetadata = M->getOrInsertNamedMetadata(OPTIMIZATION_LEVEL_MN);
+ mRSOptimizationMetadata->addOperand(
+ llvm::MDNode::get(mLLVMContext, OptimizationOption));
+
// Dump export variable info
if (mContext->hasExportVar()) {
int slotCount = 0;
diff --git a/slang_rs_backend.h b/slang_rs_backend.h
index 0dc70e6..58e4535 100644
--- a/slang_rs_backend.h
+++ b/slang_rs_backend.h
@@ -54,6 +54,7 @@
llvm::NamedMDNode *mExportTypeMetadata;
llvm::NamedMDNode *mExportElementMetadata;
llvm::NamedMDNode *mRSObjectSlotsMetadata;
+ llvm::NamedMDNode *mRSOptimizationMetadata;
RSObjectRefCount mRefCount;
diff --git a/slang_rs_metadata.h b/slang_rs_metadata.h
index 63e7e0f..4d2bd0d 100644
--- a/slang_rs_metadata.h
+++ b/slang_rs_metadata.h
@@ -33,4 +33,6 @@
#define RS_EXPORT_FOREACH_MN "#rs_export_foreach"
+#define OPTIMIZATION_LEVEL_MN "#optimization_level"
+
#endif // _FRAMEWORKS_COMPILE_SLANG_SLANG_RS_METADATA_H_ NOLINT