Re: [apache/tvm-rfcs] [RFC] Create LLVM scope class for use with LLVM libraries (PR #83)

2022-07-08 Thread Tianqi Chen
Thanks @kparzysz-quic . Sorry for the delayed reply since we are taking break 
here.

Overall I like the direction we are going. Just to figure out the spectrum of 
possible APIs

My main question is how are we going to interact with multiple ParseIR calls. 
Some example would be helpful. For example, is it OK for us to have nested 
LLVMScope

```c++
void Example() {
 LLVMScope scope1(target);
 {
  // what is the effect here, seems mod_data1 is immediate in scope
  auto mod_data1 = LLVMScope::ParseIR(name);
 }
}
```

I also wonder if there is a way to "defer" the scope initialization. e.g. can 
LLVMModule be created, stored in the LLVMScope, but the target does not take 
in-effect until we enter the scope.  We call InitializeLLVM in the constructor 
of LLVMTarget, but do other things like option setting in the enter 
stage.Something like

```c++
void Example() {
 LLVMTarget target1(target);
 auto mod_data = LLVMTarget::ParseIR(name);
 // enter target1 scope
 With scope1(target1);
 {
   // entering target in mod_data
  With scope2(mod_data);
 }
}
```
I think the main question is how coupled the operations related to LLVM are.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/apache/tvm-rfcs/pull/83#issuecomment-1178983089
You are receiving this because you are subscribed to this thread.

Message ID: 

Re: [apache/tvm-rfcs] [RFC] Name mangling in IRModules (PR #84)

2022-07-08 Thread Tianqi Chen
> Regarding the name_hint being a final name. I am too of this opinion (it 
> should be a final name) and believe that it already works this way. If I am 
> not wrong, the only edge case is where we use the global_symbol attribute 
> instead.

We should define "final name". 
In this context, it is helpful to look at existing practices. This is a topic 
related to linking in most compilers, and they are closely related to the 
linkage type.

- For a function that have ExternalLinkage, the name **cannot** change, and 
whatever name being supplied is the final name, this is because the users of 
the library needs to be able to refer to the function using the provided name.
- For a function that have PrivateLinkage, the name can and should be able to 
change, this is because when we link multiple functions together, there can be 
two private functions that comes with the same name, as a result, the 
conflicted function can be renamed. Private functions are only referred within 
the module, so we can afford to rewrite all the callers of the function to the 
new name.
- During optimization, if a function with PrivateLinkage is not called by any 
functions, we can safely remove that function, but we cannot do that for 
ExternalLinkage.

There are more linkage types in LLVM but this two types roughly are sufficient 
for our discussion purposes.

Now come back to our context, we roughly need two things:
- N0: We need an IR node to uniquely identify a function, storing hints to the 
name, so new names can be generated base on the hint, but not necessarily 
pinning down the name (due to the need to support PrivateLinkage). That is 
`GlobalVar`. 
- N1: We need a way to uniquely specify the name, or specify that the linkage 
type of the function is external.


Note that N0 means we cannot simply enforce a `name`  or `name_hint` field to 
be final, it have to be a combination with another attribute that derives the 
linkage type. So our current convention is:

- When a function have `global_symbol` attribute, it specifies the "final 
name"(as in symbol in the symbol tabel), and indicate that the LinkageType is 
External
- When a function does not have `global_symbol` attribute, it means the 
LinkageType is private, at some time point, the compiler can choose to pick the 
final name, by attaching global symbol based on the `name_hint` of the 
function. But that should be deferred to as late as possible so we can perform 
optimizations like eliminate dead functions.





-- 
Reply to this email directly or view it on GitHub:
https://github.com/apache/tvm-rfcs/pull/84#issuecomment-1178996339
You are receiving this because you are subscribed to this thread.

Message ID: 

Re: [apache/tvm] [ci][docker] Use RFC image tags only (PR #11938)

2022-07-08 Thread github-actions[bot]
It has been a while since this PR was updated, @Mousius @areusch please leave a 
review or address the outstanding comments. @driazati if this PR is still a 
work in progress, please [convert it to a 
draft](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/changing-the-stage-of-a-pull-request#converting-a-pull-request-to-a-draft)
 until it is ready for review.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/apache/tvm/pull/11938#issuecomment-1179123573
You are receiving this because you are subscribed to this thread.

Message ID: 

Re: [apache/tvm-rfcs] [RFC] Create LLVM scope class for use with LLVM libraries (PR #83)

2022-07-08 Thread Krzysztof Parzyszek
Both `LoadIR` or `ParseIR` take an optional pre-existing `LLVMContext`, and 
return a pair `{llvm::Module, LLVMScope}`, where the scope object in the pair 
is newly constructed, and contains the given `LLVMContext` (or create a new one 
if none was given).  In the first call to `ParseIR`, the caller can take the 
second element of the pair and just use it as the scope.  In a subsequent call, 
the caller can simply discard the second element, which will then be 
automatically destroyed.
An example of calling `ParseIR` or `LoadIR` when a LLVM scope already exists is 
in [`HandleImport` in 
codegen_llvm.cc](https://github.com/apache/tvm/pull/11933/files#diff-f61b04b100f5145f2681340c81d3f2af221239594ed01e2e24896522329ce92cR275).

You bring up a good point about when the scope "takes effect", or binds to 
LLVM.  I propose that the scope becomes active when a new `LLVMContext` is 
created (i.e. the scope is really determined by `LLVMContext`, not by the 
`LLVMScope`).  We could also define "takes effect" to mean that locks (or 
failure-to-create object) could be acquired.  That would mean that `ParseIR` 
and `LoadIR` return an active scope.  Also, if they are called with a context 
argument (meaning that they are called from an active scope), they wouldn't 
need to create a new context, and so they wouldn't block (if we were to add 
locks).  In such case they would return another scope object with the same 
`LLVMContext`.  This shouldn't cause any problems even if both scope objects 
were used, but could make the code confusing to read.  If we follow the 
convention that the "extra" scope is to be ignored, this would avoid the 
confusion.  There may be details to be sorted out about releasing locks, etc, 
but those are implementation details.

_Side note: Ideally, prior to the activation of the scope, none of LLVM code or 
data types would be exposed to the user, but this RFC doesn't try to go that 
far.  The main concern here is a platform on which saving/restoring LLVM flags 
could be done._

I also suggest to create two classes: `LLVMScope` and `LLVMTarget`.  The 
`LLVMTarget` would contain all the LLVM target flags and options, while 
`LLVMScope` would deal with activation, `ParseIR` and `LoadIR`.  The 
`LLVMTarget` object could be passed around, copied, etc (without concerns about 
locking or activating anything), and its purpose would be to have all the 
target flags/options in one place, and it could only exist once scope has been 
activated.

Something like
```C++
class LLVMTarget {
public:
  LLVMTarget(const LLVMTarget&);  // copy ctor, etc.

private:
  friend class LLVMScope;
  LLVMTarget(ctx, values extracted from tvm::Target);

  std::shared_ptr ctx_;// set via the private ctor, 
passed from LLVMContext
  llvm::TargetMachine *tm;
  ...
};

class LLVMScope {
public:
  LLVMScope(const Target& target) {
// Parse the target into individual attributes, e.g. mtriple, etc. This 
would allow users
// to create LLVMScope from Target and modify it before creating LLVMTarget.
//
// If the target has non-empty list of LLVM flags, it would be considered 
"modifying"
// the global state, otherwise it would be "read-only".  This would allow 
creating
// multiple "read-only" concurrent scopes, but only one "modifying" one.
  }

  void activate() {
 ctx_ = std::shared_ptr(CreateNewContext(is_read_only));
  }

  static std::pair ParseIR(std::string ir) {   // same 
for LoadIR
auto ctx = std::shared_ptr(CreateNewContext(false 
/*assume modifying*/));
llvm::Module m = llvm::parse_string_etc(ctx, ...)
LLVMScope scp(ctx, get_target_string(m));   // create an already active 
scope
return {m, scp};
  }

  LLVMTarget getTargetInfo() {
ICHECK(ctx_ != nullptr) << "must activate first";
...
  }

private:
  static llvm::LLVMContext* CreateNewContext(bool is_read_only) {
 // Create context with appropriate locking
  }
 
  LLVMScope(std::shared_ptr ctx, const Target& target);
  std::shared_ptr ctx_;
};
```


-- 
Reply to this email directly or view it on GitHub:
https://github.com/apache/tvm-rfcs/pull/83#issuecomment-1179203419
You are receiving this because you are subscribed to this thread.

Message ID: 

Re: [apache/tvm-rfcs] [RFC] Create LLVM scope class for use with LLVM libraries (PR #83)

2022-07-08 Thread Krzysztof Parzyszek
To address the second question: we shouldn't allow nesting of LLVM scopes.  The 
reason is that if the target doesn't specify any command line flags, the 
assumption is that it will rely on LLVM's defaults.  If we were to nest scopes, 
and the outer scope did modify flags, then the inner scope (without flags) 
would not have a way of knowing that the global state has been altered.

-- 
Reply to this email directly or view it on GitHub:
https://github.com/apache/tvm-rfcs/pull/83#issuecomment-1179206731
You are receiving this because you are subscribed to this thread.

Message ID: 

Re: [apache/tvm-rfcs] [RFC] Create LLVM scope class for use with LLVM libraries (PR #83)

2022-07-08 Thread Tianqi Chen
Just to followup, why does ParseIR require activation of a scope, or is it 
possible that ParseIR returns a tuple of Target and Module, where activation is 
done separately.

I am asking this mainly to see if we can get an explicit With style API

-- 
Reply to this email directly or view it on GitHub:
https://github.com/apache/tvm-rfcs/pull/83#issuecomment-1179234699
You are receiving this because you are subscribed to this thread.

Message ID: 

Re: [apache/tvm-rfcs] [RFC] Create LLVM scope class for use with LLVM libraries (PR #83)

2022-07-08 Thread Krzysztof Parzyszek
> Just to followup, why does ParseIR require activation of a scope, or is it 
> possible that ParseIR returns a tuple of Target and Module, where activation 
> is done separately.

The reason is that `ParseIR` needs to make calls to LLVM functions to create 
the `llvm::Module`.


-- 
Reply to this email directly or view it on GitHub:
https://github.com/apache/tvm-rfcs/pull/83#issuecomment-1179274109
You are receiving this because you are subscribed to this thread.

Message ID: