Adding a collector name attribute to Function in the IR. These

methods are new to Function:

  bool hasCollector() const;
  const std::string &getCollector() const;
  void setCollector(const std::string &);
  void clearCollector();

The assembly representation is as such:

  define void @f() gc "shadow-stack" { ...

The implementation uses an on-the-side table to map Functions to 
collector names, such that there is no overhead. A StringPool is 
further used to unique collector names, which are extremely
likely to be unique per process.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@44769 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Gordon Henriksen 2007-12-10 03:18:06 +00:00
parent afba8fe662
commit 80a75bfae9
21 changed files with 1468 additions and 1250 deletions

View File

@ -282,6 +282,8 @@ external is_intrinsic : llvalue -> bool = "llvm_is_intrinsic"
external function_call_conv : llvalue -> int = "llvm_function_call_conv"
external set_function_call_conv : int -> llvalue -> unit
= "llvm_set_function_call_conv"
external collector : llvalue -> string option = "llvm_collector"
external set_collector : string option -> llvalue -> unit = "llvm_set_collector"
(* TODO: param attrs *)

View File

@ -754,6 +754,15 @@ external function_call_conv : llvalue -> int = "llvm_function_call_conv"
external set_function_call_conv : int -> llvalue -> unit
= "llvm_set_function_call_conv"
(** [collector f] returns [Some name] if the function [f] has a garbage
collection algorithm specified and [None] otherwise.
See the method [llvm::Function::getCollector]. **)
external collector : llvalue -> string option = "llvm_collector"
(** [set_collector gc f] sets the collection algorithm for the function [f] to
[gc]. See the method [llvm::Function::setCollector]. **)
external set_collector : string option -> llvalue -> unit = "llvm_set_collector"
(*--... Operations on basic blocks .........................................--*)
(** [basic_blocks fn] returns the basic blocks of the function [f].

View File

@ -536,6 +536,29 @@ CAMLprim value llvm_set_function_call_conv(value Id, LLVMValueRef Fn) {
return Val_unit;
}
/* llvalue -> string option */
CAMLprim value llvm_collector(LLVMValueRef Fn) {
const char *Collector;
CAMLparam0();
CAMLlocal2(Name, Option);
if ((Collector = LLVMGetCollector(Fn))) {
Name = copy_string(Collector);
Option = alloc(1, 0);
Field(Option, 0) = Name;
CAMLreturn(Option);
} else {
CAMLreturn(Val_int(0));
}
}
/* string option -> llvalue -> unit */
CAMLprim value llvm_set_collector(value GC, LLVMValueRef Fn) {
LLVMSetCollector(Fn, GC == Val_int(0)? 0 : String_val(Field(GC, 0)));
return Val_unit;
}
/*--... Operations on basic blocks .........................................--*/
/* llvalue -> llbasicblock array */

View File

@ -26,6 +26,7 @@
<li><a href="#functionstructure">Functions</a></li>
<li><a href="#aliasstructure">Aliases</a>
<li><a href="#paramattrs">Parameter Attributes</a></li>
<li><a href="#gc">Garbage Collector Names</a></li>
<li><a href="#moduleasm">Module-Level Inline Assembly</a></li>
<li><a href="#datalayout">Data Layout</a></li>
</ol>
@ -702,15 +703,16 @@ an optional <a href="#linkage">linkage type</a>, an optional
<a href="#paramattrs">parameter attribute</a> for the return type, a function
name, a (possibly empty) argument list (each with optional
<a href="#paramattrs">parameter attributes</a>), an optional section, an
optional alignment, an opening curly brace, a list of basic blocks, and a
closing curly brace.
optional alignment, an optional <a href="gc">garbage collector name</a>, an
opening curly brace, a list of basic blocks, and a closing curly brace.
LLVM function declarations consist of the "<tt>declare</tt>" keyword, an
optional <a href="#linkage">linkage type</a>, an optional
<a href="#visibility">visibility style</a>, an optional
<a href="#callingconv">calling convention</a>, a return type, an optional
<a href="#paramattrs">parameter attribute</a> for the return type, a function
name, a possibly empty list of arguments, and an optional alignment.</p>
name, a possibly empty list of arguments, an optional alignment, and an optional
<a href="gc">garbage collector name</a>.</p>
<p>A function definition contains a list of basic blocks, forming the CFG for
the function. Each basic block may optionally start with a label (giving the
@ -824,6 +826,23 @@ declare i32 @atoi(i8*) nounwind readonly
</div>
<!-- ======================================================================= -->
<div class="doc_subsection">
<a name="gc">Garbage Collector Names</a>
</div>
<div class="doc_text">
<p>Each function may specify a garbage collector name, which is simply a
string.</p>
<div class="doc_code"><pre
>define void @f() gc "name" { ...</pre></div>
<p>The compiler declares the supported values of <i>name</i>. Specifying a
collector which will cause the compiler to alter its output in order to support
the named garbage collection algorithm.</p>
</div>
<!-- ======================================================================= -->
<div class="doc_subsection">
<a name="moduleasm">Module-Level Inline Assembly</a>

View File

@ -339,6 +339,8 @@ LLVMValueRef LLVMGetParam(LLVMValueRef Fn, unsigned Index);
unsigned LLVMGetIntrinsicID(LLVMValueRef Fn);
unsigned LLVMGetFunctionCallConv(LLVMValueRef Fn);
void LLVMSetFunctionCallConv(LLVMValueRef Fn, unsigned CC);
const char *LLVMGetCollector(LLVMValueRef Fn);
void LLVMSetCollector(LLVMValueRef Fn, const char *Coll);
/* Operations on basic blocks */
LLVMValueRef LLVMBasicBlockAsValue(LLVMBasicBlockRef Bb);

View File

@ -58,7 +58,9 @@ namespace bitc {
MODULE_CODE_ALIAS = 9,
/// MODULE_CODE_PURGEVALS: [numvals]
MODULE_CODE_PURGEVALS = 10
MODULE_CODE_PURGEVALS = 10,
MODULE_CODE_COLLECTORNAME = 11 // COLLECTORNAME: [strchr x N]
};
/// PARAMATTR blocks have code for defining a parameter attribute set.

View File

@ -153,6 +153,13 @@ public:
/// @brief Set the parameter attributes.
void setParamAttrs(const ParamAttrsList *attrs);
/// hasCollector/getCollector/setCollector/clearCollector - The name of the
/// garbage collection algorithm to use during code generation.
bool hasCollector() const;
const char *getCollector() const;
void setCollector(const char *Str);
void clearCollector();
/// @brief Determine whether the function has the given attribute.
bool paramHasAttr(uint16_t i, ParameterAttributes attr) const {
return ParamAttrs && ParamAttrs->paramHasAttr(i, attr);

View File

@ -468,6 +468,7 @@ int LLLexer::LexIdentifier() {
KEYWORD("module", MODULE);
KEYWORD("asm", ASM_TOK);
KEYWORD("sideeffect", SIDEEFFECT);
KEYWORD("gc", GC);
KEYWORD("cc", CC_TOK);
KEYWORD("ccc", CCC_TOK);

File diff suppressed because it is too large Load Diff

View File

@ -181,9 +181,10 @@
NEST = 397,
READNONE = 398,
READONLY = 399,
DEFAULT = 400,
HIDDEN = 401,
PROTECTED = 402
GC = 400,
DEFAULT = 401,
HIDDEN = 402,
PROTECTED = 403
};
#endif
/* Tokens. */
@ -329,16 +330,17 @@
#define NEST 397
#define READNONE 398
#define READONLY 399
#define DEFAULT 400
#define HIDDEN 401
#define PROTECTED 402
#define GC 400
#define DEFAULT 401
#define HIDDEN 402
#define PROTECTED 403
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
#line 945 "/home/asl/proj/llvm/src/lib/AsmParser/llvmAsmParser.y"
#line 945 "/Users/malichus/Source/llvm/src/llvm/lib/AsmParser/llvmAsmParser.y"
{
llvm::Module *ModuleVal;
llvm::Function *FunctionVal;
@ -385,8 +387,8 @@ typedef union YYSTYPE
llvm::ICmpInst::Predicate IPredicate;
llvm::FCmpInst::Predicate FPredicate;
}
/* Line 1489 of yacc.c. */
#line 390 "llvmAsmParser.tab.h"
/* Line 1529 of yacc.c. */
#line 392 "llvmAsmParser.tab.h"
YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1

View File

@ -1046,7 +1046,7 @@ Module *llvm::RunVMAsmParser(llvm::MemoryBuffer *MB) {
%token<StrVal> STRINGCONSTANT ATSTRINGCONSTANT PCTSTRINGCONSTANT
%type <StrVal> LocalName OptLocalName OptLocalAssign
%type <StrVal> GlobalName OptGlobalAssign GlobalAssign
%type <StrVal> OptSection SectionString
%type <StrVal> OptSection SectionString OptGC
%type <UIntVal> OptAlign OptCAlign
@ -1090,7 +1090,7 @@ Module *llvm::RunVMAsmParser(llvm::MemoryBuffer *MB) {
// Function Attributes
%token SIGNEXT ZEROEXT NORETURN INREG SRET NOUNWIND NOALIAS BYVAL NEST
%token READNONE READONLY
%token READNONE READONLY GC
// Visibility Styles
%token DEFAULT HIDDEN PROTECTED
@ -1244,6 +1244,12 @@ OptFuncAttrs : /* empty */ { $$ = ParamAttr::None; }
}
;
OptGC : /* empty */ { $$ = 0; }
| GC STRINGCONSTANT {
$$ = $2;
}
;
// OptAlign/OptCAlign - An optional alignment, and an optional alignment with
// a comma before it.
OptAlign : /*empty*/ { $$ = 0; } |
@ -2225,7 +2231,7 @@ ArgList : ArgListH {
};
FunctionHeaderH : OptCallingConv ResultTypes GlobalName '(' ArgList ')'
OptFuncAttrs OptSection OptAlign {
OptFuncAttrs OptSection OptAlign OptGC {
std::string FunctionName(*$3);
delete $3; // Free strdup'd memory!
@ -2328,6 +2334,10 @@ FunctionHeaderH : OptCallingConv ResultTypes GlobalName '(' ArgList ')'
Fn->setSection(*$8);
delete $8;
}
if ($10) {
Fn->setCollector($10->c_str());
delete $10;
}
// Add all of the arguments we parsed to the function...
if ($5) { // Is null if empty...

View File

@ -1046,7 +1046,7 @@ Module *llvm::RunVMAsmParser(llvm::MemoryBuffer *MB) {
%token<StrVal> STRINGCONSTANT ATSTRINGCONSTANT PCTSTRINGCONSTANT
%type <StrVal> LocalName OptLocalName OptLocalAssign
%type <StrVal> GlobalName OptGlobalAssign GlobalAssign
%type <StrVal> OptSection SectionString
%type <StrVal> OptSection SectionString OptGC
%type <UIntVal> OptAlign OptCAlign
@ -1090,7 +1090,7 @@ Module *llvm::RunVMAsmParser(llvm::MemoryBuffer *MB) {
// Function Attributes
%token SIGNEXT ZEROEXT NORETURN INREG SRET NOUNWIND NOALIAS BYVAL NEST
%token READNONE READONLY
%token READNONE READONLY GC
// Visibility Styles
%token DEFAULT HIDDEN PROTECTED
@ -1244,6 +1244,12 @@ OptFuncAttrs : /* empty */ { $$ = ParamAttr::None; }
}
;
OptGC : /* empty */ { $$ = 0; }
| GC STRINGCONSTANT {
$$ = $2;
}
;
// OptAlign/OptCAlign - An optional alignment, and an optional alignment with
// a comma before it.
OptAlign : /*empty*/ { $$ = 0; } |
@ -2225,7 +2231,7 @@ ArgList : ArgListH {
};
FunctionHeaderH : OptCallingConv ResultTypes GlobalName '(' ArgList ')'
OptFuncAttrs OptSection OptAlign {
OptFuncAttrs OptSection OptAlign OptGC {
std::string FunctionName(*$3);
delete $3; // Free strdup'd memory!
@ -2328,6 +2334,10 @@ FunctionHeaderH : OptCallingConv ResultTypes GlobalName '(' ArgList ')'
Fn->setSection(*$8);
delete $8;
}
if ($10) {
Fn->setCollector($10->c_str());
delete $10;
}
// Add all of the arguments we parsed to the function...
if ($5) { // Is null if empty...

View File

@ -849,6 +849,7 @@ bool BitcodeReader::ParseModule(const std::string &ModuleID) {
SmallVector<uint64_t, 64> Record;
std::vector<std::string> SectionTable;
std::vector<std::string> CollectorTable;
// Read all the records for this module.
while (!Stream.AtEndOfStream()) {
@ -974,6 +975,13 @@ bool BitcodeReader::ParseModule(const std::string &ModuleID) {
SectionTable.push_back(S);
break;
}
case bitc::MODULE_CODE_COLLECTORNAME: { // SECTIONNAME: [strchr x N]
std::string S;
if (ConvertToString(Record, 0, S))
return Error("Invalid MODULE_CODE_COLLECTORNAME record");
CollectorTable.push_back(S);
break;
}
// GLOBALVAR: [type, isconst, initid,
// linkage, alignment, section, visibility, threadlocal]
case bitc::MODULE_CODE_GLOBALVAR: {
@ -1016,7 +1024,7 @@ bool BitcodeReader::ParseModule(const std::string &ModuleID) {
break;
}
// FUNCTION: [type, callingconv, isproto, linkage, paramattr,
// alignment, section, visibility]
// alignment, section, visibility, collector]
case bitc::MODULE_CODE_FUNCTION: {
if (Record.size() < 8)
return Error("Invalid MODULE_CODE_FUNCTION record");
@ -1044,6 +1052,11 @@ bool BitcodeReader::ParseModule(const std::string &ModuleID) {
Func->setSection(SectionTable[Record[6]-1]);
}
Func->setVisibility(GetDecodedVisibility(Record[7]));
if (Record.size() > 8 && Record[8]) {
if (Record[8]-1 > CollectorTable.size())
return Error("Invalid collector ID");
Func->setCollector(CollectorTable[Record[8]-1].c_str());
}
ValueList.push_back(Func);

View File

@ -297,9 +297,10 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
WriteStringRecord(bitc::MODULE_CODE_ASM, M->getModuleInlineAsm(),
0/*TODO*/, Stream);
// Emit information about sections, computing how many there are. Also
// compute the maximum alignment value.
// Emit information about sections and collectors, computing how many there
// are. Also compute the maximum alignment value.
std::map<std::string, unsigned> SectionMap;
std::map<std::string, unsigned> CollectorMap;
unsigned MaxAlignment = 0;
unsigned MaxGlobalType = 0;
for (Module::const_global_iterator GV = M->global_begin(),E = M->global_end();
@ -317,13 +318,24 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
}
for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) {
MaxAlignment = std::max(MaxAlignment, F->getAlignment());
if (!F->hasSection()) continue;
// Give section names unique ID's.
unsigned &Entry = SectionMap[F->getSection()];
if (Entry != 0) continue;
WriteStringRecord(bitc::MODULE_CODE_SECTIONNAME, F->getSection(),
0/*TODO*/, Stream);
Entry = SectionMap.size();
if (F->hasSection()) {
// Give section names unique ID's.
unsigned &Entry = SectionMap[F->getSection()];
if (!Entry) {
WriteStringRecord(bitc::MODULE_CODE_SECTIONNAME, F->getSection(),
0/*TODO*/, Stream);
Entry = SectionMap.size();
}
}
if (F->hasCollector()) {
// Same for collector names.
unsigned &Entry = CollectorMap[F->getCollector()];
if (!Entry) {
WriteStringRecord(bitc::MODULE_CODE_COLLECTORNAME, F->getCollector(),
0/*TODO*/, Stream);
Entry = CollectorMap.size();
}
}
}
// Emit abbrev for globals, now that we know # sections and max alignment.
@ -383,7 +395,7 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
// Emit the function proto information.
for (Module::const_iterator F = M->begin(), E = M->end(); F != E; ++F) {
// FUNCTION: [type, callingconv, isproto, paramattr,
// linkage, alignment, section, visibility]
// linkage, alignment, section, visibility, collector]
Vals.push_back(VE.getTypeID(F->getType()));
Vals.push_back(F->getCallingConv());
Vals.push_back(F->isDeclaration());
@ -392,6 +404,7 @@ static void WriteModuleInfo(const Module *M, const ValueEnumerator &VE,
Vals.push_back(Log2_32(F->getAlignment())+1);
Vals.push_back(F->hasSection() ? SectionMap[F->getSection()] : 0);
Vals.push_back(getEncodedVisibility(F));
Vals.push_back(F->hasCollector() ? CollectorMap[F->getCollector()] : 0);
unsigned AbbrevToUse = 0;
Stream.EmitRecord(bitc::MODULE_CODE_FUNCTION, Vals, AbbrevToUse);

View File

@ -67,6 +67,8 @@ Module *llvm::CloneModule(const Module *M,
GlobalValue::ExternalLinkage, I->getName(), New);
NF->setCallingConv(I->getCallingConv());
NF->setParamAttrs(I->getParamAttrs());
if (I->hasCollector())
NF->setCollector(I->getCollector());
ValueMap[I]= NF;
}

View File

@ -1112,6 +1112,8 @@ void AssemblyWriter::printFunction(const Function *F) {
Out << " section \"" << F->getSection() << '"';
if (F->getAlignment())
Out << " align " << F->getAlignment();
if (F->hasCollector())
Out << " gc \"" << F->getCollector() << '"';
if (F->isDeclaration()) {
Out << "\n";

View File

@ -619,6 +619,19 @@ void LLVMSetFunctionCallConv(LLVMValueRef Fn, unsigned CC) {
return unwrap<Function>(Fn)->setCallingConv(CC);
}
const char *LLVMGetCollector(LLVMValueRef Fn) {
Function *F = unwrap<Function>(Fn);
return F->hasCollector()? F->getCollector() : 0;
}
void LLVMSetCollector(LLVMValueRef Fn, const char *Coll) {
Function *F = unwrap<Function>(Fn);
if (Coll)
F->setCollector(Coll);
else
F->clearCollector();
}
/*--.. Operations on basic blocks ..........................................--*/
LLVMValueRef LLVMBasicBlockAsValue(LLVMBasicBlockRef Bb) {

View File

@ -17,8 +17,10 @@
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/Support/LeakDetector.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/StringPool.h"
#include "SymbolTableListTraitsImpl.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringExtras.h"
using namespace llvm;
@ -297,6 +299,9 @@ Function::~Function() {
// Drop our reference to the parameter attributes, if any.
if (ParamAttrs)
ParamAttrs->dropRef();
// Remove the function from the on-the-side collector table.
clearCollector();
}
void Function::BuildLazyArguments() const {
@ -379,6 +384,40 @@ void Function::dropAllReferences() {
BasicBlocks.clear(); // Delete all basic blocks...
}
// Maintain the collector name for each function in an on-the-side table. This
// saves allocating an additional word in Function for programs which do not use
// GC (i.e., most programs) at the cost of increased overhead for clients which
// do use GC.
static DenseMap<const Function*,PooledStringPtr> *CollectorNames;
static StringPool *CollectorNamePool;
bool Function::hasCollector() const {
return CollectorNames && CollectorNames->count(this);
}
const char *Function::getCollector() const {
assert(hasCollector() && "Function has no collector");
return *(*CollectorNames)[this];
}
void Function::setCollector(const char *Str) {
if (!CollectorNamePool)
CollectorNamePool = new StringPool();
if (!CollectorNames)
CollectorNames = new DenseMap<const Function*,PooledStringPtr>();
(*CollectorNames)[this] = CollectorNamePool->intern(Str);
}
void Function::clearCollector() {
if (CollectorNames) {
CollectorNames->erase(this);
if (CollectorNames->empty()) {
delete CollectorNames;
CollectorNames = 0;
}
}
}
/// getIntrinsicID - This method returns the ID number of the specified
/// function, or Intrinsic::not_intrinsic if the function is not an
/// intrinsic, or if the pointer is null. This value is always defined to be

View File

@ -0,0 +1,12 @@
; RUN: llvm-as < %s | llvm-dis | grep {@f.*gc.*shadowstack}
; RUN: llvm-as < %s | llvm-dis | grep {@g.*gc.*java}
define void @f() gc "shadowstack" {
entry:
ret void
}
define void @g() gc "java" {
entry:
ret void
}

View File

@ -25,7 +25,8 @@ let insist cond =
exit_status := 10;
" FAIL "
end in
prerr_endline (msg ^ (string_of_int !case_num))
prerr_endline (" " ^ (string_of_int !case_num) ^ if cond then ""
else " FAIL")
let suite name f =
prerr_endline (name ^ ":");
@ -490,7 +491,20 @@ let test_functions () =
insist (ccc = function_call_conv fn);
set_function_call_conv fastcc fn;
insist (fastcc = function_call_conv fn);
ignore (build_unreachable (builder_at_end (entry_block fn)))
ignore (build_unreachable (builder_at_end (entry_block fn)));
begin group "collector";
(* RUN: grep {Fn6.*gc.*shadowstack} < %t.ll
*)
let fn = define_function "Fn6" ty m in
insist (None = collector fn);
set_collector (Some "ocaml") fn;
insist (Some "ocaml" = collector fn);
set_collector None fn;
insist (None = collector fn);
set_collector (Some "shadowstack") fn;
ignore (build_unreachable (builder_at_end (entry_block fn)));
end
(*===-- Basic Blocks ------------------------------------------------------===*)
@ -749,7 +763,6 @@ let test_builder () =
let t3 = const_vector [| one; one; zero; zero |] in
let vec1 = build_insertelement t1 p1 p2 "Vec1" atentry in
let vec2 = build_insertelement t2 p1 p2 "Vec2" atentry in
let vec3 = build_insertelement t3 p1 p2 "Vec3" atentry in
ignore (build_extractelement vec1 p2 "Inst49" atentry);
ignore (build_insertelement vec1 p1 p2 "Inst50" atentry);

View File

@ -7,7 +7,7 @@ declare void @llvm_gc_initialize(i32)
declare void @llvm.gcroot(i8**, i8*)
declare void @llvm.gcwrite(i8*, i8*, i8**)
define i32 @main() {
define i32 @main() gc "shadow-stack" {
entry:
%A = alloca i8*
%B = alloca i8**