{% extends "site.html" %} {% load displayutils %} {% block title %}contact{% endblock %} {% block content %}
Unfortunately, nowadays too many people use tapiriik to promise 1-on-1 support for synchronization problems any more - there's only one of me and a whole lot more of you!
If you are having issues with your account, please check the activity dashboard - it'll do its best to tell you what went wrong.
If you can't resolve the issue and would like your money back, use the email below to request a refund. And, if you had emailed me previously regarding your account and never received a reply, please accept my apologies.
If you're dissatisfied with the service and want a refund, make sure to mention that in the subject line so I can respond quickly.
If you are making an enquiry regarding the European Union's General Data Protection Regulation, please mention "GDPR" in the subject line.


The Brownlow Downlow.
Predicting the Most Valuable Player of the Australian Football League.
Introduction
In the Australian Football League, the Brownlow Medal is awarded to the most valuable player for the year. At the end of each game, the field umpires award "votes" to the players they regard as the top players for that game: 3 votes to the best player, 2 votes to the 2nd best player and 1 vote to the 3rd best player. At the end of the regular season, these votes are revealed and the Brownlow Medal is awarded to the player with the most votes.
Results in brief
We've established a rock solid baseline using a balanced bagging ensemble approach with a random forest as our base model. Trained and validated on 2002-2014, we correctly predicted 5 of the top 7 in 2015 test data. Definitely some outliers in there but it will provide a good benchmark going forward as we add better validation methods, try new approaches and integrate with betting market outcomes.
| Player | Team | Predicted votes | Actual votes | Predicted rank | Actual rank |
|---|---|---|---|---|---|
| Sam Mitchell | HW | 26.7 | 26 | 1 | 3 |
| Nat Fyfe | FR | 26.2 | 31 | 2 | 1 |
| Andrew Gaff | WC | 26.0 | 17 | 3 | 12 |
| Dan Hannebery | SY | 24.6 | 24 | 4 | 5 |
| Matt Priddis | WC | 23.9 | 28 | 5 | 2 |
| Lachie Neale | FR | 23.6 | 10 | 6 | 32 |
| Josh Kennedy | SY | 22.3 | 25 | 7 | 4 |
| Scott Thompson | AD | 21.0 | 12 | 8 | 25 |
| David Mundy | FR | 20.9 | 19 | 9 | 8 |
| Trent Cotchin | RI | 20.7 | 17 | 10 | 12 |
Framing the problem
Predicting the winner of the Brownlow medal can best be viewed as a "learning to rank" problem. Given a game (with 2 teams of typically 22 players), we want to predict the 1st, 2nd and 3rd best players.
It combines elements of classification, in that we have discrete target variables of "1st (3 votes)", "2nd (2 votes)", "3rd (1 vote)" and "0 votes", with regression, in that these categories still have a value and a meaningful, ordered relationship with one another.
Furthermore, given the value of these models to betting (in Australia, sports wagering is legal and AFL/Brownlow markets are highly liquid), we don't simply want to predict hard ranks to players for each game. It would be ideal if we could model "soft" rankings with uncertainty, to establish implied betting odds and expected return on investment for various markets.
Approaches
Ordinal regression
While modelling this partial ordering can be done directly using ordinal regression models, there are 3 key drawbacks to these models for our problem:
- There is no constraint on multiple players in a given game being awarded a specific vote (e.g. 2 players could be assigned "3 votes" during inference).
- For our data, the "1 vote" category, and to a slightly lesser extent the "2 vote" category, are incredibly noisy. Intuitively, this makes sense, as the "best player" is usually much easier to identify or pick than the "third best player".
- Some approaches (SVMs) assign hard votes, while other approaches (logistic regression) don't have easily interpretable soft votes; simply multiplying each vote by the probability of a player obtaining that vote leads to similar issues to those in (1).
Binary classification on "3 votes"
Another option would be to train a model only on the "3 votes" category:
- Train some probabilistic classification model
- Infer probabilities of "3 votes" classification for each player in a given game
- Map the highest probability to "3 votes", the 2nd highest to "2 votes", the 3rd highest to "1 vote" and the rest to "0 votes"
- Select model and hyperparameters according to relevant metrics on the validation set (e.g. rank MSE, F1-score for each class and globally)
There are two key drawbacks to this approach:
- Votes are hard assigned (i.e. no implied uncertainty)
- Class imbalance may impact performance of models - only 1 in ~44 (e.g. ~2%) of players are in the "3 vote" category for each game
While there are a number of ways to combat these drawbacks (some of which I believe are superior to the below and will explore at a later date), I propose a fairly simple solution to establish a solid baseline below.
A bagging-based approach
While there are many methods to combat class imbalance, a convenient solution for our problem is a balanced bagging approach (Wallace, Small, Brodley and Trikalinos).
This allows us to reduce the variance of individual bagged models by taking the average of predicted votes, while also using the entire set of predictions as a proxy for understanding the distribution of possible vote outcomes:
- Use 2015 as test data, with 2002-2014 as training and valdiation data.
- Split train/val 0.75/0.25 by game (this is key to inferring ranks)
- Within the training data, train 100 models on 100 bootstrap samples on the binary classification of "3 vote", where the majority class (non-3 vote) is undersampled.
- On the validation data, infer votes based on the ranks of P(3 vote) within each game.
- Choose best model and hyperparameters based on validation set performance.
Input variables
We used commonly available player statistics for each game - possessions (kicks/handballs, contested/uncontested), marks, goals, behinds, goal assists, one percenters etc. All individual stats were normalized within a game, since these stats are judged by umpires within the context of that game. We also included whether a player's team won the game or not, again normalized within each game for consistency. This allowed us to accurately compare the performance of models that are sensitive to scaling vs. those that aren't.
Metrics
After inferring votes, we examined learning curves as well as confusion matrices to assess the performance of our models.
While the above learning curve was for our optimal random forest model, the same general trend was true for all models examined: better accuracy and lower variance than individual undersampled bootstrap models.
Similarly, the general trend in confusion matrices was the same: models performed well for "0 votes", reasonably well for "3 votes", but not well for "1 vote" and "2 votes". This is something we can definitely improve on in the future.
While this is useful for examining the performance of individual models (monitoring bias/variance, accuracy), it is challenging to compare many different models and hyperparameters at once. We instead chose summary statistics closely related to the above:
- Vote MSE by vote category and on average (arithmetic, geometric and global)
- F1-score by vote category and on average (arithmetic, geometric and global)
Model validation
We performed hyperparameter grid search across a number of classification models with a probabilistic output (required for game ranking and votes): Gaussian Naive Bayes, Logistic Regression, Decision Trees, Random Forests. In the future it would be great to incorporate SVMs by ranking players within a game by distance to the separating hyperplane, but given we are just setting a baseline right now it can wait. Due to resource constraints (i.e. my MacBook Air), we used a reduced 30 bootstrap samples to compare models. The top two performing models on the validation set are below:
- Logistic Regression with L2 penalty and C = 1
- Random Forest with 30 trees, max depth of 30, sqrt max features, min samples per split of 10, min samples per leaf of 1, bootstrap on
We ultimately chose the random forest model. While it generally underperformed in the F1 score (i.e. it had a higher misclassification rate), it outperformed in MSE. This implies that even though the RF model had more misclassifications in aggregate, the misclassifications were, on average, closer to the ground truth (especially on 1 and 2 votes).
Test set results
| Player | Team | Predicted votes | Actual votes | Predicted rank | Actual rank |
|---|---|---|---|---|---|
| Sam Mitchell | HW | 26.7 | 26 | 1 | 3 |
| Nat Fyfe | FR | 26.2 | 31 | 2 | 1 |
| Andrew Gaff | WC | 26.0 | 17 | 3 | 12 |
| Dan Hannebery | SY | 24.6 | 24 | 4 | 5 |
| Matt Priddis | WC | 23.9 | 28 | 5 | 2 |
| Lachie Neale | FR | 23.6 | 10 | 6 | 32 |
| Josh Kennedy | SY | 22.3 | 25 | 7 | 4 |
| Scott Thompson | AD | 21.0 | 12 | 8 | 25 |
| David Mundy | FR | 20.9 | 19 | 9 | 8 |
| Trent Cotchin | RI | 20.7 | 17 | 10 | 12 |
What's next?
- A more comprehensive validation process. Given that voting trends change over time, it is likely that some voting signals decay. We will compare different sliding lookback windows on the training/validation set.
- Roughly balanced bagging, a method more aligned to the original bagging technique that samples the majority class based on a negative binomial distribution.
- Single model (gradient boosting, neural nets), simulation based approaches (e.g. a generalization of the Gumbel-max trick appears promising).


steghide extract -sf <image>
enter for blank passphrase
hydra with WP login brute / POST request for websites
hydra -l <user> -P list.txt <ip> http-post-form "/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log+In&redirect_to=http%3A%2F%2F<IP_ADDRESS>%2Fwp-admin%2F&testcookie=1:is incorrect"
http-post-form is the module
/wp-login.php is the login page
between the semi colons is the Data for the POST request, with ^USER^ and ^PASS^
is incorrect is for detection of a failed login (appears on page with incorrect login)
wp:
malicious plugins
Edit PHP files in Appearance Editor (themes are php files)
writeable /etc/passwd
either change root passwd or create a new line with UID/GID 0
openssl passwd -1 -salt ippsec hackthebox
ippsec:$1$ojfoawijefoa;iwjfeoi:0:0:root:/root:/bin/bash
su ippsec


Joy Hou [@] [LinkedIn] [GitHub]
Hi, I'm Joy!  I have enjoyed careers as an attorney and a mortgage loan originator. In my spare time, I salsa dance, hike, practice martial arts, run, play video games, read, write, create, and play. My favorite color is pink, my favorite liquor is tequila, and my favorite book is "The Name of The Wind" by Patrick Rothfuss. I love summer dresses, warm beaches, the touch of sunlight on my skin, fluffy animals, good reads, and pretty pictures. I have a sassy cat named Snowdrop, a rambunctuous dog named Toby, and a usually awesome but sometimes just tolerable husband named Adam.
Templates
Colors
Backgrounds
There is a different background image for each color theme. Adjust your colors to change the image.


#Include - A techno-learning club associated with talent, knowledge and learning is the official club of Information Technology Department.
We are a collaboration of ardent technophiles and zealous learners who believe that the central purpose of education, learning and collaboration is to mediate voluntary evolution. We believe that an investment in knowledge is the best thing an individual can do. We try to provide the best possible environment for students to reach their maximum potential and to chisel their abilities to the best of their capacities.
S.G.S.I.T.S. Indore
23, Sir M. Visvesvaraya Marg, Vallabh Nagar,
Indore, Madhya
Pradesh
452003


Cavs guard Porter suspended 1 game for bumping official
by TOM WITHERSCLEVELAND (AP) - Cavaliers rookie guard Kevin Porter Jr. has been suspended by the NBA for one game without pay for bumping an official.
At the end of the third quarter of Cleveland’s 131-111 loss to Dallas on Sunday night, Porter brushed into referee Bill Spooner’s shoulder as he ran back down the floor after missing a shot. The contact knocked Spooner off balance, and he immediately looked at Porter, who didn’t turn around.
The league announced the discipline for Porter on Monday.
The Cavs drafted the 19-year-old Porter with the No. 30 overall pick in this year’s draft. Considered one of the most talented players available, he was passed over by some teams after being suspended for conduct issues at Southern California. He played 21 games for the Trojans.
Porter is averaging 5.3 points in six games for the Cavs, who host the Boston Celtics on Tuesday night.
More AP NBA: https://apnews.com/NBA and https://twitter.com/AP_NBA
Sign up for Daily Newsletters
Copyright © 2019 The Washington Times, LLC.
Please read our comment policy before commenting.


IT professional with a passion for tech innovation and problem solving through software development. Full Stack developer with applicable hands on experience in Python, MEANjs, MERNjs, Java, HTML/CSS and Bootstrap through the development of dozens of projects.
Ever since I published my first "Hello World" in 2010, I was hooked. Regardless of what I was doing at the time, whether it was Acting, Modeling or working in sales, I have always been drawn to the tech field.. specifically programming. I continue to sharpen my skills on a daily basis by completing projects and working on algorithms. I'm looking forward to collaborating with other IT professionals to advance technology
A fullstack MEANjs web application that allows users to log in and create posts based on catagories. This application helps new technical trainers avoid common rookie mistakes by learning from more seasoned Technical Trainers.
Click Here to view on GitHubJavaScript web application that allows users to pick a new random quote each time they click. This application utilizes Html, CSS, Bootstrap and JavaScript to pull quotes from a quote API.
Click Here to view on CodePenJarvis is a backend Python personal assistant application. Jarvis can perform simple arithmatic, suggest sports based on the specified number of players, guess your age, track your eating habbits and suggest healthier meals if necessary.
Click Here to view on GitHubA front end weather application that shows users the weather, their location and displays a background image based on the current temperature. This application uses Html, CSS, Bootstrap and JavaScript.
Click Here to view on CodePen


A Wizard of Oz experiment is a research experiment in which subjects interact with a computer system that subjects believe to be autonomous, but which is actually being operated or partially operated by an unseen human being
As you see on the attached screenshot, the WoZ tool displays a screen full of buttons, where each button corresponds to a character response. A WoZ operator (wizard) pushes a button and triggers the response that can either be a playback of an audio recording, a video clip, or an animation sequence handled Smartbody and rendering engine. The WoZ tool does not do any media playback itself. It relies on an external component to handle the media. From the technical point, each button has an associated vhmsg that is triggered when the button is pushed. For example, it can be a vrExpress message with a video clip file name supplied as a parameter. We have a separate VideoPlayer tool that listens for vrExpress messages, parses the message content, finds the video file with the right name, and plays it on the screen.
The buttons are arranged into rows, where every row has a title. The rows are arranged into screens, where every screen has a title. You can specify buttons that trigger transitions between the screens. The same button can appear in multiple rows and the same row can appear on multiple screens.
TBD
TBD
You can pass WoZ parameters via the query arguments in the URL. Here are some of the arguments:
true
or false
whether to automatically
generate an extra row for switching between individual screens. The
default value is true
.
true
or false
whether to show the chat
transcript panel. The
default value is true
for connector=ADConnector
and false
in other cases.
VHMSG
,
ConsoleConnector
, and ADConnector
localhost
.
DEFAULT_SCOPE
.
true
or false
token
to specify whether
the connection is
secure. The default value is true
.
To help an operator to locate relevant buttons WoZ has... TBD
The data for the wizard comes from several tables (as in database tables) and can be created as an Excel or Google Sheet spreadsheet. Each table should be defined as separate sheet in the spreadsheet. The following sheets can be defined. 3 of the sheets are required and 1 is optional.
Multiple WoZ datasets are allowed per a single Excel document. Each dataset must have its own button, row, and screen sheets. The row and button sheets are mandatory.
The name of the sheets are important. For example, "foo.buttons" specifies the button sheet for dataset "foo".
A sheet that uses the plain "buttons", "rows", or "screens" name will be merged with the corresponding sheet from each dataset. For example, "foo.buttons" will be merged with the content of the sheet "buttons".
A sheet with the name "buttons" specifies all the buttons in the interface. Each row corresponds to a single button and the columns map to button's attributes. The first row contains the column headers. The following column (and the corresponding headers) are required:
The following attributes are optional:
The following screenshot shows a regular button definition
The following screenshot shows how transition buttons can be defined in the sheet.
If the "woz.vhmsg" column is omitted, WoZ will send a vrExpress populated with id and tooltip. If columns "woz.sender" and "woz.addressee" are present, WoZ will use those values to fill the appropriate parts of the message. If the columns are omitted WoZ uses values "visitor" and "all". The message content can be specified explicitly or it can be defined as a template using the values in other columns as variables. For example, the default behavior can be reproduced by using
vrExpress $$sender$$ $$addressee$$ $$sender$$$$messageCount$$ <?xml version="1.0" encoding="UTF-8" standalone="no" ?><act><participant id="$$XML(sender)$$" role="actor" /><fml><turn start="take" end="give" /><affect type="neutral" target="addressee"></affect><culture type="neutral"></culture><personality type="neutral"></personality></fml> <bml><speech id="sp1" ref="$$XML(id)$$" type="application/ssml+xml"> $$XML(tooltip)$$ </speech></bml></act>
Here the content of column "woz.sender" will be the second token in the message and so on. Note that the variable name omits "woz."from the column title.
Note that in case when the message contains XML code, you need to make the content of the variables is encoded appropriately when inserted into the message. We introduce XML(•) to indicate those cases. For example, $$XML(sender)$$ will take the content of woz.sender column and encode is as valid XML (e.g., replace "<" with "<") before inserting it into the message.
A button can trigger a dialog box with popup buttons and text fields for
the operator to fill. For example, if the tooltip column contains a token
that looks like ##token##
, when the operator clicks on the
button, she will be presented with a dialog box, with the text of the
tooltip where each ##token##
is replaced by a text entry
field. After entering information into the field, the user can press the Send
button on the dialog to send the modified text in the vhmsg. In the following
example the tooltip column contains "Let's start. ##input##".
The token
expression in the ##token##
expression
serves as
the variable name that can be used in message generation. (See the previous
section.) You can define as many variables as you want, the variable names
are case-sensitive. If the variable name matches a column name in the
button sheet, the entered value will overwrite the value in the column.
The ##token##
expression results in a text entry field added
to the dialog. If you want to limit the set of possible values, you can
instruct WoZ to generate popup menu instead of the text entry. In this case
use an expression like this: ##token;value1;value2;value3##
.
Here the variable with the name "token" can take one of the 3 values:
value1, value2, or value3. And the dialog box will include a popup menu
with 3 items.
If you want the items in the menu be different from the actual values
assigned to the variable, use both the value and the item text separated by
colon ":". For example, ##token;value1:Item
1;value2:Another Item;
value3:And one more item##
. The menu will have three items: "Item
1", "Another Item", and "And one more item."
You can specify the buttons for transitions between screens by hand as described in the previous section, but sometimes it would be better to generate them automatically from the content of the screens sheet (see the Screen Sheet section for the details). You can do something like this:
| J | K (woz.id) | L (woz.label) | M (woz.color) | O (woz.transition) | |
|---|---|---|---|---|---|
| 2900 | =ROW() |   |   |   |   |
| 2901 | =FLOOR((ROW()-J$2900-1)/2,1)+1 | =IF(J2901<=COUNTA(screens!$1:$1), CONCATENATE("transition.",N2901),"") |
=INDEX(screens!$1:$2,2,J2901) | color.tab | =INDEX(screens!$1:$2,1,J2901) |
| 2902 | =FLOOR((ROW()-J$2900-1)/2,1)+1 | =IF(J2902<=COUNTA(screens!$1:$1), CONCATENATE("transition.",N2902,".selected"),"") |
=INDEX(screens!$1:$2,2,J2902) | color.tab.selected | =INDEX(screens!$1:$2,1,J2902) |
Repeat the last two lines for every screen on the screen sheet (copy the last two rows and keep pasting them until the cells in the woz.id column starts showing up empty. Make sure you adjust the column and row references appropriately.
You should get something like this:
A sheet with the name "rows" specifies all the button rows in the interface. Each Excel table row corresponds to a single row in the interface. The first column contains the row ID, the second column contains the row title, the rest of the columns contain the row's buttons, one button ID per cell. The order of the buttons in the WoZ interface will be the same as the order of the buttons in the Excel table. Note that the first row in the table is an actual row in the WoZ interface. It specifies buttons that transition between different screens. Also note the different number of buttons in each row. For example, row 11 contains just one button, while row 3 references at least three buttons.
You can specify the tab row (the row with buttons that transition between screens) by hand as described in the previous section, but sometimes it would be better to generate them automatically from the content of the screens sheet (see the Screen Sheet section for the details). You can do something like this:
|   | A | B | C |
|---|---|---|---|
| 230 |   | =ROW() |   |
| 231 | =IF(ROW()-$B$230<=COUNTA(screens!$1:$1), CONCATENATE("tab.",INDEX(screens!$1:$1,1,ROW()-$B$230)),"") |
Screens | =IF(OR(ROW()-$B$230>COUNTA(screens!$1:$1),COLUMN()-2>COUNTA(screens!$1:$1)),"", CONCATENATE("transition.",INDEX(screens!$1:$1,1,COLUMN()-2),IF(ROW()-$B$230=COLUMN()-2,".selected",""))) |
You can have the same tab row for every screen. You can also elect to build tab rows that are different for individual screens. For example, you may want to highlight the button corresponding to the current screen with special color. That what the table illustrates. This will generate a tab row for every screen.
Suppose N is the number of screens, you need to copy the row (231) N times. And, then copy the column (C) N times. You should get something like this:
A sheet with the name "screens" specifies all the button screens in the interface. Each Excel table column corresponds to a single screen in the interface. The first row in the column contains the screen ID, the second row contains the screen title, the rest of the rows contain the screen's rows, one row ID per cell. The order of the rows in the WoZ interface will be the same as the order of the rows in the Excel table. Note how the first row (id "tab.row") is the same across multiple screens.
If you are generating the tab rows using Excel formulas as described in the previous section, you can insert the tab row into the screen sheet as shown in the table.
|   | A | B |
|---|---|---|
| 1 | Intro | Pre-War |
| 2 | Intro | Pre-War |
| 3 | =CONCATENATE("tab.",A1) | =CONCATENATE("tab.",B1) |
A sheet with the name "colors" specifies all the button colors in the interface. Each Excel table row corresponds to a single color in the interface. The first column contains the color ID, the other three columns specify the color component values either as RGB or HSB tuples. The first row in the table contains the column headers. The attached screenshot shows the colors defined by the hue, saturation, and brightness values. If you want to use RGB, put "red", "green", and "blue" in the corresponding column titles.
Some suggested to use Excel cell styles and background color to specify the colors for the buttons. Due to the extremely archaic way Excel stores and handles colors (don't ask) extracting the color component values that would result in colors that look anywhere close to the cell background proved extremely difficult, nigh impossible.


--- page: name: 'Billion Oyster Project' title: 'Billion Oyster Project' description: 'Curriculum Management and Data Collection/Publishing tool for the Billion Oyster Project' url: 'http://platform.bop.nyc' includes: head: /_includes/head.html navbar: /_includes/navbar.html user-navbar: /_includes/user-navbar.html bindings: - name: 'user' resource: '/api/users/me' not_if: '{{ eqx $.request.url.path "/authentication/signin" }}' optional: true fallback: {} if_status: 401: '{{ if match $.page.security.private_pages $.request.url.path }}/authentication/signin?p={{ $.request.url.path }}{{ else }}continue{{ end }}' flags: admin: '{{ has "admin" $.bindings.user.roles }}' teamLead: '{{ has "team lead" $.bindings.user.roles }}' teamLeadPending: '{{ has "team lead pending" $.bindings.user.roles }}' teamMember: '{{ has "team member" $.bindings.user.roles }}' teamMemberPending: '{{ has "team member pending" $.bindings.user.roles }}' partner: '{{ has "partner" $.bindings.user.roles }}' loggedIn: '{{ if $.bindings.user }}true{{ end }}' ---
{{ template "head" . }}


Enyim Memcached Version History
Version 2.7
- Removed log4net from the project and made the log provider configurable. See http://github.com/enyim/EnyimMemcached/wiki/Configure-Logging
- Fixed the config section to default to the Binary protocol. (The MemcachedClientConfiguration was already doing this for some time.)
- The client no longer checks if objects are larger than 1MB, but lets the server sort it out


Laurent Rönn
Home
DevBlog
Portfolio
About
Welcome!
I design and create
This is definitely where you parked your car. And also where the magic happens.
Browse around to view some of my projects.
The pages are being updated so expect more to come!
For querys and information, please contact me at:
<EMAIL_ADDRESS>DevBlog
Portfolio
About


This document describes techniques for writing compiler backends that convert the LLVM IR (intermediate representation) to code for a specified machine or other languages. Code intended for a specific machine can take the form of either assembly code or binary code (usable for a JIT compiler).
The backend of LLVM features a target-independent code generator that may create output for several types of target CPUs, including X86, PowerPC, Alpha, and SPARC. The backend may also be used to generate code targeted at SPUs of the Cell processor or GPUs to support the execution of compute kernels.
The document focuses on existing examples found in subdirectories of llvm/lib/Target in a downloaded LLVM release. In particular, this document focuses on the example of creating a static compiler (one that emits text assembly) for a SPARC target, because SPARC has fairly standard characteristics, such as a RISC instruction set and straightforward calling conventions.
The audience for this document is anyone who needs to write an LLVM backend to generate code for a specific hardware or software target.
To write a compiler backend for LLVM that converts the LLVM IR (intermediate representation) to code for a specified target (machine or other language), follow these steps:
In the .cpp and .h files, initially stub up these methods and then implement them later. Initially, you may not know which private members that the class will need and which components will need to be subclassed.
To actually create your compiler backend, you need to create and modify a few files. The absolute minimum is discussed here, but to actually use the LLVM target-independent code generator, you must perform the steps described in the LLVM Target-Independent Code Generator document.
First, you should create a subdirectory under lib/Target to hold all the files related to your target. If your target is called "Dummy", create the directory lib/Target/Dummy.
In this new directory, create a Makefile. It is easiest to copy a Makefile of another target and modify it. It should at least contain the LEVEL, LIBRARYNAME and TARGET variables, and then include $(LEVEL)/Makefile.common. The library can be named LLVMDummy (for example, see the MIPS target). Alternatively, you can split the library into LLVMDummyCodeGen and LLVMDummyAsmPrinter, the latter of which should be implemented in a subdirectory below lib/Target/Dummy (for example, see the PowerPC target).
Note that these two naming schemes are hardcoded into llvm-config. Using any other naming scheme will confuse llvm-config and produce lots of (seemingly unrelated) linker errors when linking llc.
To make your target actually do something, you need to implement a subclass of TargetMachine. This implementation should typically be in the file lib/Target/DummyTargetMachine.cpp, but any file in the lib/Target directory will be built and should work. To use LLVM's target independent code generator, you should do what all current machine backends do: create a subclass of LLVMTargetMachine. (To create a target from scratch, create a subclass of TargetMachine.)
To get LLVM to actually build and link your target, you need to add it to the TARGETS_TO_BUILD variable. To do this, you modify the configure script to know about your target when parsing the --enable-targets option. Search the configure script for TARGETS_TO_BUILD, add your target to the lists there (some creativity required) and then reconfigure. Alternatively, you can change autotools/configure.ac and regenerate configure by running ./autoconf/AutoRegen.sh
LLVMTargetMachine is designed as a base class for targets implemented with the LLVM target-independent code generator. The LLVMTargetMachine class should be specialized by a concrete target class that implements the various virtual methods. LLVMTargetMachine is defined as a subclass of TargetMachine in include/llvm/Target/TargetMachine.h. The TargetMachine class implementation (TargetMachine.cpp) also processes numerous command-line options.
To create a concrete target-specific subclass of LLVMTargetMachine, start by copying an existing TargetMachine class and header. You should name the files that you create to reflect your specific target. For instance, for the SPARC target, name the files SparcTargetMachine.h and SparcTargetMachine.cpp
For a target machine XXX, the implementation of XXXTargetMachine must have access methods to obtain objects that represent target components. These methods are named get*Info and are intended to obtain the instruction set (getInstrInfo), register set (getRegisterInfo), stack frame layout (getFrameInfo), and similar information. XXXTargetMachine must also implement the getTargetData method to access an object with target-specific data characteristics, such as data type size and alignment requirements.
For instance, for the SPARC target, the header file SparcTargetMachine.h declares prototypes for several get*Info and getTargetData methods that simply return a class member.
namespace llvm { class Module; class SparcTargetMachine : public LLVMTargetMachine { const TargetData DataLayout; // Calculates type size & alignment SparcSubtarget Subtarget; SparcInstrInfo InstrInfo; TargetFrameInfo FrameInfo; protected: virtual const TargetAsmInfo *createTargetAsmInfo() const; public: SparcTargetMachine(const Module &M, const std::string &FS); virtual const SparcInstrInfo *getInstrInfo() const {return &InstrInfo; } virtual const TargetFrameInfo *getFrameInfo() const {return &FrameInfo; } virtual const TargetSubtarget *getSubtargetImpl() const{return &Subtarget; } virtual const TargetRegisterInfo *getRegisterInfo() const { return &InstrInfo.getRegisterInfo(); } virtual const TargetData *getTargetData() const { return &DataLayout; } static unsigned getModuleMatchQuality(const Module &M); // Pass Pipeline Configuration virtual bool addInstSelector(PassManagerBase &PM, bool Fast); virtual bool addPreEmitPass(PassManagerBase &PM, bool Fast); virtual bool addAssemblyEmitter(PassManagerBase &PM, bool Fast, std::ostream &Out); }; } // end namespace llvm
For some targets, you also need to support the following methods:
In addition, the XXXTargetMachine constructor should specify a TargetDescription string that determines the data layout for the target machine, including characteristics such as pointer size, alignment, and endianness. For example, the constructor for SparcTargetMachine contains the following:
SparcTargetMachine::SparcTargetMachine(const Module &M, const std::string &FS) : DataLayout("E-p:32:32-f128:128:128"), Subtarget(M, FS), InstrInfo(Subtarget), FrameInfo(TargetFrameInfo::StackGrowsDown, 8, 0) { }
Hyphens separate portions of the TargetDescription string.
You must also register your target using the RegisterTarget template. (See the TargetMachineRegistry class.) For example, in SparcTargetMachine.cpp, the target is registered with:
namespace { // Register the target. RegisterTarget<SparcTargetMachine>X("sparc", "SPARC"); }
You should describe a concrete target-specific class that represents the register file of a target machine. This class is called XXXRegisterInfo (where XXX identifies the target) and represents the class register file data that is used for register allocation and also describes the interactions between registers.
You also need to define register classes to categorize related registers. A register class should be added for groups of registers that are all treated the same way for some instruction. Typical examples are register classes that include integer, floating-point, or vector registers. A register allocator allows an instruction to use any register in a specified register class to perform the instruction in a similar manner. Register classes allocate virtual registers to instructions from these sets, and register classes let the target-independent register allocator automatically choose the actual registers.
Much of the code for registers, including register definition, register aliases, and register classes, is generated by TableGen from XXXRegisterInfo.td input files and placed in XXXGenRegisterInfo.h.inc and XXXGenRegisterInfo.inc output files. Some of the code in the implementation of XXXRegisterInfo requires hand-coding.
The XXXRegisterInfo.td file typically starts with register definitions for a target machine. The Register class (specified in Target.td) is used to define an object for each register. The specified string n becomes the Name of the register. The basic Register object does not have any subregisters and does not specify any aliases.
class Register<string n> { string Namespace = ""; string AsmName = n; string Name = n; int SpillSize = 0; int SpillAlignment = 0; list<Register> Aliases = []; list<Register> SubRegs = []; list<int> DwarfNumbers = []; }
For example, in the X86RegisterInfo.td file, there are register definitions that utilize the Register class, such as:
def AL : Register<"AL">, DwarfRegNum<[0, 0, 0]>;
This defines the register AL and assigns it values (with DwarfRegNum) that are used by gcc, gdb, or a debug information writer (such as DwarfWriter in llvm/lib/CodeGen) to identify a register. For register AL, DwarfRegNum takes an array of 3 values, representing 3 different modes: the first element is for X86-64, the second for EH (exception handling) on X86-32, and the third is generic. -1 is a special Dwarf number that indicates the gcc number is undefined, and -2 indicates the register number is invalid for this mode.
From the previously described line in the X86RegisterInfo.td file, TableGen generates this code in the X86GenRegisterInfo.inc file:
static const unsigned GR8[] = { X86::AL, ... }; const unsigned AL_AliasSet[] = { X86::AX, X86::EAX, X86::RAX, 0 }; const TargetRegisterDesc RegisterDescriptors[] = { ... { "AL", "AL", AL_AliasSet, Empty_SubRegsSet, Empty_SubRegsSet, AL_SuperRegsSet }, ...
From the register info file, TableGen generates a TargetRegisterDesc object for each register. TargetRegisterDesc is defined in include/llvm/Target/TargetRegisterInfo.h with the following fields:
struct TargetRegisterDesc { const char *AsmName; // Assembly language name for the register const char *Name; // Printable name for the reg (for debugging) const unsigned *AliasSet; // Register Alias Set const unsigned *SubRegs; // Sub-register set const unsigned *ImmSubRegs; // Immediate sub-register set const unsigned *SuperRegs; // Super-register set };
TableGen uses the entire target description file (.td) to determine text names for the register (in the AsmName and Name fields of TargetRegisterDesc) and the relationships of other registers to the defined register (in the other TargetRegisterDesc fields). In this example, other definitions establish the registers "AX", "EAX", and "RAX" as aliases for one another, so TableGen generates a null-terminated array (AL_AliasSet) for this register alias set.
The Register class is commonly used as a base class for more complex classes. In Target.td, the Register class is the base for the RegisterWithSubRegs class that is used to define registers that need to specify subregisters in the SubRegs list, as shown here:
class RegisterWithSubRegs<string n, list<Register> subregs> : Register<n> { let SubRegs = subregs; }
In SparcRegisterInfo.td, additional register classes are defined for SPARC: a Register subclass, SparcReg, and further subclasses: Ri, Rf, and Rd. SPARC registers are identified by 5-bit ID numbers, which is a feature common to these subclasses. Note the use of ‘let’ expressions to override values that are initially defined in a superclass (such as SubRegs field in the Rd class).
class SparcReg<string n> : Register<n> { field bits<5> Num; let Namespace = "SP"; } // Ri - 32-bit integer registers class Ri<bits<5> num, string n> : SparcReg<n> { let Num = num; } // Rf - 32-bit floating-point registers class Rf<bits<5> num, string n> : SparcReg<n> { let Num = num; } // Rd - Slots in the FP register file for 64-bit floating-point values. class Rd<bits<5> num, string n, list<Register> subregs> : SparcReg<n> { let Num = num; let SubRegs = subregs; }
In the SparcRegisterInfo.td file, there are register definitions that utilize these subclasses of Register, such as:
def G0 : Ri< 0, "G0">, DwarfRegNum<[0]>; def G1 : Ri< 1, "G1">, DwarfRegNum<[1]>; ... def F0 : Rf< 0, "F0">, DwarfRegNum<[32]>; def F1 : Rf< 1, "F1">, DwarfRegNum<[33]>; ... def D0 : Rd< 0, "F0", [F0, F1]>, DwarfRegNum<[32]>; def D1 : Rd< 2, "F2", [F2, F3]>, DwarfRegNum<[34]>;
The last two registers shown above (D0 and D1) are double-precision floating-point registers that are aliases for pairs of single-precision floating-point sub-registers. In addition to aliases, the sub-register and super-register relationships of the defined register are in fields of a register’s TargetRegisterDesc.
The RegisterClass class (specified in Target.td) is used to define an object that represents a group of related registers and also defines the default allocation order of the registers. A target description file XXXRegisterInfo.td that uses Target.td can construct register classes using the following class:
class RegisterClass<string namespace, list<ValueType> regTypes, int alignment, list<Register> regList> { string Namespace = namespace; list<ValueType> RegTypes = regTypes; int Size = 0; // spill size, in bits; zero lets tblgen pick the size int Alignment = alignment; // CopyCost is the cost of copying a value between two registers // default value 1 means a single instruction // A negative value means copying is extremely expensive or impossible int CopyCost = 1; list<Register> MemberList = regList; // for register classes that are subregisters of this class list<RegisterClass> SubRegClassList = []; code MethodProtos = [{}]; // to insert arbitrary code code MethodBodies = [{}]; }
To define a RegisterClass, use the following 4 arguments:
In SparcRegisterInfo.td, three RegisterClass objects are defined: FPRegs, DFPRegs, and IntRegs. For all three register classes, the first argument defines the namespace with the string “SP”. FPRegs defines a group of 32 single-precision floating-point registers (F0 to F31); DFPRegs defines a group of 16 double-precision registers (D0-D15). For IntRegs, the MethodProtos and MethodBodies methods are used by TableGen to insert the specified code into generated output.
def FPRegs : RegisterClass<"SP", [f32], 32, [F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15, F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31]>; def DFPRegs : RegisterClass<"SP", [f64], 64, [D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15]>; def IntRegs : RegisterClass<"SP", [i32], 32, [L0, L1, L2, L3, L4, L5, L6, L7, I0, I1, I2, I3, I4, I5, O0, O1, O2, O3, O4, O5, O7, G1, // Non-allocatable regs: G2, G3, G4, O6, // stack ptr I6, // frame ptr I7, // return address G0, // constant zero G5, G6, G7 // reserved for kernel ]> { let MethodProtos = [{ iterator allocation_order_end(const MachineFunction &MF) const; }]; let MethodBodies = [{ IntRegsClass::iterator IntRegsClass::allocation_order_end(const MachineFunction &MF) const { return end()-10 // Don't allocate special registers -1; } }]; }
Using SparcRegisterInfo.td with TableGen generates several output files that are intended for inclusion in other source code that you write. SparcRegisterInfo.td generates SparcGenRegisterInfo.h.inc, which should be included in the header file for the implementation of the SPARC register implementation that you write (SparcRegisterInfo.h). In SparcGenRegisterInfo.h.inc a new structure is defined called SparcGenRegisterInfo that uses TargetRegisterInfo as its base. It also specifies types, based upon the defined register classes: DFPRegsClass, FPRegsClass, and IntRegsClass.
SparcRegisterInfo.td also generates SparcGenRegisterInfo.inc, which is included at the bottom of SparcRegisterInfo.cpp, the SPARC register implementation. The code below shows only the generated integer registers and associated register classes. The order of registers in IntRegs reflects the order in the definition of IntRegs in the target description file. Take special note of the use of MethodBodies in SparcRegisterInfo.td to create code in SparcGenRegisterInfo.inc. MethodProtos generates similar code in SparcGenRegisterInfo.h.inc.
// IntRegs Register Class... static const unsigned IntRegs[] = { SP::L0, SP::L1, SP::L2, SP::L3, SP::L4, SP::L5, SP::L6, SP::L7, SP::I0, SP::I1, SP::I2, SP::I3, SP::I4, SP::I5, SP::O0, SP::O1, SP::O2, SP::O3, SP::O4, SP::O5, SP::O7, SP::G1, SP::G2, SP::G3, SP::G4, SP::O6, SP::I6, SP::I7, SP::G0, SP::G5, SP::G6, SP::G7, }; // IntRegsVTs Register Class Value Types... static const MVT::ValueType IntRegsVTs[] = { MVT::i32, MVT::Other }; namespace SP { // Register class instances DFPRegsClass DFPRegsRegClass; FPRegsClass FPRegsRegClass; IntRegsClass IntRegsRegClass; ... // IntRegs Sub-register Classess... static const TargetRegisterClass* const IntRegsSubRegClasses [] = { NULL }; ... // IntRegs Super-register Classess... static const TargetRegisterClass* const IntRegsSuperRegClasses [] = { NULL }; // IntRegs Register Class sub-classes... static const TargetRegisterClass* const IntRegsSubclasses [] = { NULL }; ... // IntRegs Register Class super-classes... static const TargetRegisterClass* const IntRegsSuperclasses [] = { NULL }; ... IntRegsClass::iterator IntRegsClass::allocation_order_end(const MachineFunction &MF) const { return end()-10 // Don't allocate special registers -1; } IntRegsClass::IntRegsClass() : TargetRegisterClass(IntRegsRegClassID, IntRegsVTs, IntRegsSubclasses, IntRegsSuperclasses, IntRegsSubRegClasses, IntRegsSuperRegClasses, 4, 4, 1, IntRegs, IntRegs + 32) {} }
The final step is to hand code portions of XXXRegisterInfo, which implements the interface described in TargetRegisterInfo.h. These functions return 0, NULL, or false, unless overridden. Here’s a list of functions that are overridden for the SPARC implementation in SparcRegisterInfo.cpp:
During the early stages of code generation, the LLVM IR code is converted to a SelectionDAG with nodes that are instances of the SDNode class containing target instructions. An SDNode has an opcode, operands, type requirements, and operation properties (for example, is an operation commutative, does an operation load from memory). The various operation node types are described in the include/llvm/CodeGen/SelectionDAGNodes.h file (values of the NodeType enum in the ISD namespace).
TableGen uses the following target description (.td) input files to generate much of the code for instruction definition:
There is also a target-specific XXX.td file, where XXX is the name of the target. The XXX.td file includes the other .td input files, but its contents are only directly important for subtargets.
You should describe a concrete target-specific class XXXInstrInfo that represents machine instructions supported by a target machine. XXXInstrInfo contains an array of XXXInstrDescriptor objects, each of which describes one instruction. An instruction descriptor defines:
The Instruction class (defined in Target.td) is mostly used as a base for more complex instruction classes.
class Instruction { string Namespace = ""; dag OutOperandList; // An dag containing the MI def operand list. dag InOperandList; // An dag containing the MI use operand list. string AsmString = ""; // The .s format to print the instruction with. list<dag> Pattern; // Set to the DAG pattern for this instruction list<Register> Uses = []; list<Register> Defs = []; list<Predicate> Predicates = []; // predicates turned into isel match code ... remainder not shown for space ... }
A SelectionDAG node (SDNode) should contain an object representing a target-specific instruction that is defined in XXXInstrInfo.td. The instruction objects should represent instructions from the architecture manual of the target machine (such as the SPARC Architecture Manual for the SPARC target).
A single instruction from the architecture manual is often modeled as multiple target instructions, depending upon its operands. For example, a manual might describe an add instruction that takes a register or an immediate operand. An LLVM target could model this with two instructions named ADDri and ADDrr.
You should define a class for each instruction category and define each opcode as a subclass of the category with appropriate parameters such as the fixed binary encoding of opcodes and extended opcodes. You should map the register bits to the bits of the instruction in which they are encoded (for the JIT). Also you should specify how the instruction should be printed when the automatic assembly printer is used.
As is described in the SPARC Architecture Manual, Version 8, there are three major 32-bit formats for instructions. Format 1 is only for the CALL instruction. Format 2 is for branch on condition codes and SETHI (set high bits of a register) instructions. Format 3 is for other instructions.
Each of these formats has corresponding classes in SparcInstrFormat.td. InstSP is a base class for other instruction classes. Additional base classes are specified for more precise formats: for example in SparcInstrFormat.td, F2_1 is for SETHI, and F2_2 is for branches. There are three other base classes: F3_1 for register/register operations, F3_2 for register/immediate operations, and F3_3 for floating-point operations. SparcInstrInfo.td also adds the base class Pseudo for synthetic SPARC instructions.
SparcInstrInfo.td largely consists of operand and instruction definitions for the SPARC target. In SparcInstrInfo.td, the following target description file entry, LDrr, defines the Load Integer instruction for a Word (the LD SPARC opcode) from a memory address to a register. The first parameter, the value 3 (112), is the operation value for this category of operation. The second parameter (0000002) is the specific operation value for LD/Load Word. The third parameter is the output destination, which is a register operand and defined in the Register target description file (IntRegs).
def LDrr : F3_1 <3, 0b000000, (outs IntRegs:$dst), (ins MEMrr:$addr), "ld [$addr], $dst", [(set IntRegs:$dst, (load ADDRrr:$addr))]>;
The fourth parameter is the input source, which uses the address operand MEMrr that is defined earlier in SparcInstrInfo.td:
def MEMrr : Operand<i32> { let PrintMethod = "printMemOperand"; let MIOperandInfo = (ops IntRegs, IntRegs); }
The fifth parameter is a string that is used by the assembly printer and can be left as an empty string until the assembly printer interface is implemented. The sixth and final parameter is the pattern used to match the instruction during the SelectionDAG Select Phase described in (The LLVM Target-Independent Code Generator). This parameter is detailed in the next section, Instruction Selector.
Instruction class definitions are not overloaded for different operand types, so separate versions of instructions are needed for register, memory, or immediate value operands. For example, to perform a Load Integer instruction for a Word from an immediate operand to a register, the following instruction class is defined:
def LDri : F3_2 <3, 0b000000, (outs IntRegs:$dst), (ins MEMri:$addr), "ld [$addr], $dst", [(set IntRegs:$dst, (load ADDRri:$addr))]>;
Writing these definitions for so many similar instructions can involve a lot of cut and paste. In td files, the multiclass directive enables the creation of templates to define several instruction classes at once (using the defm directive). For example in SparcInstrInfo.td, the multiclass pattern F3_12 is defined to create 2 instruction classes each time F3_12 is invoked:
multiclass F3_12 <string OpcStr, bits<6> Op3Val, SDNode OpNode> { def rr : F3_1 <2, Op3Val, (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), !strconcat(OpcStr, " $b, $c, $dst"), [(set IntRegs:$dst, (OpNode IntRegs:$b, IntRegs:$c))]>; def ri : F3_2 <2, Op3Val, (outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c), !strconcat(OpcStr, " $b, $c, $dst"), [(set IntRegs:$dst, (OpNode IntRegs:$b, simm13:$c))]>; }
So when the defm directive is used for the XOR and ADD instructions, as seen below, it creates four instruction objects: XORrr, XORri, ADDrr, and ADDri.
defm XOR : F3_12<"xor", 0b000011, xor>; defm ADD : F3_12<"add", 0b000000, add>;
SparcInstrInfo.td also includes definitions for condition codes that are referenced by branch instructions. The following definitions in SparcInstrInfo.td indicate the bit location of the SPARC condition code; for example, the 10th bit represents the ‘greater than’ condition for integers, and the 22nd bit represents the ‘greater than’ condition for floats.
def ICC_NE : ICC_VAL< 9>; // Not Equal def ICC_E : ICC_VAL< 1>; // Equal def ICC_G : ICC_VAL<10>; // Greater ... def FCC_U : FCC_VAL<23>; // Unordered def FCC_G : FCC_VAL<22>; // Greater def FCC_UG : FCC_VAL<21>; // Unordered or Greater ...
(Note that Sparc.h also defines enums that correspond to the same SPARC condition codes. Care must be taken to ensure the values in Sparc.h correspond to the values in SparcInstrInfo.td; that is, SPCC::ICC_NE = 9, SPCC::FCC_U = 23 and so on.)
The code generator backend maps instruction operands to fields in the instruction. Operands are assigned to unbound fields in the instruction in the order they are defined. Fields are bound when they are assigned a value. For example, the Sparc target defines the XNORrr instruction as a F3_1 format instruction having three operands.
def XNORrr : F3_1<2, 0b000111, (outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c), "xnor $b, $c, $dst", [(set IntRegs:$dst, (not (xor IntRegs:$b, IntRegs:$c)))]>;
The instruction templates in SparcInstrFormats.td show the base class for F3_1 is InstSP.
class InstSP<dag outs, dag ins, string asmstr, list<dag> pattern> : Instruction { field bits<32> Inst; let Namespace = "SP"; bits<2> op; let Inst{31-30} = op; dag OutOperandList = outs; dag InOperandList = ins; let AsmString = asmstr; let Pattern = pattern; }
InstSP leaves the op field unbound.
class F3<dag outs, dag ins, string asmstr, list<dag> pattern> : InstSP<outs, ins, asmstr, pattern> { bits<5> rd; bits<6> op3; bits<5> rs1; let op{1} = 1; // Op = 2 or 3 let Inst{29-25} = rd; let Inst{24-19} = op3; let Inst{18-14} = rs1; }
F3 binds the op field and defines the rd, op3, and rs1 fields. F3 format instructions will bind the operands rd, op3, and rs1 fields.
class F3_1<bits<2> opVal, bits<6> op3val, dag outs, dag ins, string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { bits<8> asi = 0; // asi not currently used bits<5> rs2; let op = opVal; let op3 = op3val; let Inst{13} = 0; // i field = 0 let Inst{12-5} = asi; // address space identifier let Inst{4-0} = rs2; }
F3_1 binds the op3 field and defines the rs2 fields. F3_1 format instructions will bind the operands to the rd, rs1, and rs2 fields. This results in the XNORrr instruction binding $dst, $b, and $c operands to the rd, rs1, and rs2 fields respectively.
The final step is to hand code portions of XXXInstrInfo, which implements the interface described in TargetInstrInfo.h. These functions return 0 or a Boolean or they assert, unless overridden. Here's a list of functions that are overridden for the SPARC implementation in SparcInstrInfo.cpp:
Performance can be improved by combining instructions or by eliminating instructions that are never reached. The AnalyzeBranch method in XXXInstrInfo may be implemented to examine conditional instructions and remove unnecessary instructions. AnalyzeBranch looks at the end of a machine basic block (MBB) for opportunities for improvement, such as branch folding and if conversion. The BranchFolder and IfConverter machine function passes (see the source files BranchFolding.cpp and IfConversion.cpp in the lib/CodeGen directory) call AnalyzeBranch to improve the control flow graph that represents the instructions.
Several implementations of AnalyzeBranch (for ARM, Alpha, and X86) can be examined as models for your own AnalyzeBranch implementation. Since SPARC does not implement a useful AnalyzeBranch, the ARM target implementation is shown below.
AnalyzeBranch returns a Boolean value and takes four parameters:
In the simplest case, if a block ends without a branch, then it falls through to the successor block. No destination blocks are specified for either TBB or FBB, so both parameters return NULL. The start of the AnalyzeBranch (see code below for the ARM target) shows the function parameters and the code for the simplest case.
bool ARMInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, std::vector<MachineOperand> &Cond) const { MachineBasicBlock::iterator I = MBB.end(); if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) return false;
If a block ends with a single unconditional branch instruction, then AnalyzeBranch (shown below) should return the destination of that branch in the TBB parameter.
if (LastOpc == ARM::B || LastOpc == ARM::tB) { TBB = LastInst->getOperand(0).getMBB(); return false; }
If a block ends with two unconditional branches, then the second branch is never reached. In that situation, as shown below, remove the last branch instruction and return the penultimate branch in the TBB parameter.
if ((SecondLastOpc == ARM::B || SecondLastOpc==ARM::tB) && (LastOpc == ARM::B || LastOpc == ARM::tB)) { TBB = SecondLastInst->getOperand(0).getMBB(); I = LastInst; I->eraseFromParent(); return false; }
A block may end with a single conditional branch instruction that falls through to successor block if the condition evaluates to false. In that case, AnalyzeBranch (shown below) should return the destination of that conditional branch in the TBB parameter and a list of operands in the Cond parameter to evaluate the condition.
if (LastOpc == ARM::Bcc || LastOpc == ARM::tBcc) { // Block ends with fall-through condbranch. TBB = LastInst->getOperand(0).getMBB(); Cond.push_back(LastInst->getOperand(1)); Cond.push_back(LastInst->getOperand(2)); return false; }
If a block ends with both a conditional branch and an ensuing unconditional branch, then AnalyzeBranch (shown below) should return the conditional branch destination (assuming it corresponds to a conditional evaluation of ‘true’) in the TBB parameter and the unconditional branch destination in the FBB (corresponding to a conditional evaluation of ‘false’). A list of operands to evaluate the condition should be returned in the Cond parameter.
unsigned SecondLastOpc = SecondLastInst->getOpcode(); if ((SecondLastOpc == ARM::Bcc && LastOpc == ARM::B) || (SecondLastOpc == ARM::tBcc && LastOpc == ARM::tB)) { TBB = SecondLastInst->getOperand(0).getMBB(); Cond.push_back(SecondLastInst->getOperand(1)); Cond.push_back(SecondLastInst->getOperand(2)); FBB = LastInst->getOperand(0).getMBB(); return false; }
For the last two cases (ending with a single conditional branch or ending with one conditional and one unconditional branch), the operands returned in the Cond parameter can be passed to methods of other instructions to create new branches or perform other operations. An implementation of AnalyzeBranch requires the helper methods RemoveBranch and InsertBranch to manage subsequent operations.
AnalyzeBranch should return false indicating success in most circumstances. AnalyzeBranch should only return true when the method is stumped about what to do, for example, if a block has three terminating branches. AnalyzeBranch may return true if it encounters a terminator it cannot handle, such as an indirect branch.
LLVM uses a SelectionDAG to represent LLVM IR instructions, and nodes of the SelectionDAG ideally represent native target instructions. During code generation, instruction selection passes are performed to convert non-native DAG instructions into native target-specific instructions. The pass described in XXXISelDAGToDAG.cpp is used to match patterns and perform DAG-to-DAG instruction selection. Optionally, a pass may be defined (in XXXBranchSelector.cpp) to perform similar DAG-to-DAG operations for branch instructions. Later, the code in XXXISelLowering.cpp replaces or removes operations and data types not supported natively (legalizes) in a Selection DAG.
TableGen generates code for instruction selection using the following target description input files:
The implementation of an instruction selection pass must include a header that declares the FunctionPass class or a subclass of FunctionPass. In XXXTargetMachine.cpp, a Pass Manager (PM) should add each instruction selection pass into the queue of passes to run.
The LLVM static compiler (llc) is an excellent tool for visualizing the contents of DAGs. To display the SelectionDAG before or after specific processing phases, use the command line options for llc, described at SelectionDAG Instruction Selection Process.
To describe instruction selector behavior, you should add patterns for lowering LLVM code into a SelectionDAG as the last parameter of the instruction definitions in XXXInstrInfo.td. For example, in SparcInstrInfo.td, this entry defines a register store operation, and the last parameter describes a pattern with the store DAG operator.
def STrr : F3_1< 3, 0b000100, (outs), (ins MEMrr:$addr, IntRegs:$src), "st $src, [$addr]", [(store IntRegs:$src, ADDRrr:$addr)]>;
ADDRrr is a memory mode that is also defined in SparcInstrInfo.td:
def ADDRrr : ComplexPattern<i32, 2, "SelectADDRrr", [], []>;
The definition of ADDRrr refers to SelectADDRrr, which is a function defined in an implementation of the Instructor Selector (such as SparcISelDAGToDAG.cpp).
In lib/Target/TargetSelectionDAG.td, the DAG operator for store is defined below:
def store : PatFrag<(ops node:$val, node:$ptr), (st node:$val, node:$ptr), [{ if (StoreSDNode *ST = dyn_cast<StoreSDNode>(N)) return !ST->isTruncatingStore() && ST->getAddressingMode() == ISD::UNINDEXED; return false; }]>;
XXXInstrInfo.td also generates (in XXXGenDAGISel.inc) the SelectCode method that is used to call the appropriate processing method for an instruction. In this example, SelectCode calls Select_ISD_STORE for the ISD::STORE opcode.
SDNode *SelectCode(SDValue N) { ... MVT::ValueType NVT = N.getNode()->getValueType(0); switch (N.getOpcode()) { case ISD::STORE: { switch (NVT) { default: return Select_ISD_STORE(N); break; } break; } ...
The pattern for STrr is matched, so elsewhere in XXXGenDAGISel.inc, code for STrr is created for Select_ISD_STORE. The Emit_22 method is also generated in XXXGenDAGISel.inc to complete the processing of this instruction.
SDNode *Select_ISD_STORE(const SDValue &N) { SDValue Chain = N.getOperand(0); if (Predicate_store(N.getNode())) { SDValue N1 = N.getOperand(1); SDValue N2 = N.getOperand(2); SDValue CPTmp0; SDValue CPTmp1; // Pattern: (st:void IntRegs:i32:$src, // ADDRrr:i32:$addr)<<P:Predicate_store>> // Emits: (STrr:void ADDRrr:i32:$addr, IntRegs:i32:$src) // Pattern complexity = 13 cost = 1 size = 0 if (SelectADDRrr(N, N2, CPTmp0, CPTmp1) && N1.getNode()->getValueType(0) == MVT::i32 && N2.getNode()->getValueType(0) == MVT::i32) { return Emit_22(N, SP::STrr, CPTmp0, CPTmp1); } ...
The Legalize phase converts a DAG to use types and operations that are natively supported by the target. For natively unsupported types and operations, you need to add code to the target-specific XXXTargetLowering implementation to convert unsupported types and operations to supported ones.
In the constructor for the XXXTargetLowering class, first use the addRegisterClass method to specify which types are supports and which register classes are associated with them. The code for the register classes are generated by TableGen from XXXRegisterInfo.td and placed in XXXGenRegisterInfo.h.inc. For example, the implementation of the constructor for the SparcTargetLowering class (in SparcISelLowering.cpp) starts with the following code:
addRegisterClass(MVT::i32, SP::IntRegsRegisterClass); addRegisterClass(MVT::f32, SP::FPRegsRegisterClass); addRegisterClass(MVT::f64, SP::DFPRegsRegisterClass);
You should examine the node types in the ISD namespace (include/llvm/CodeGen/SelectionDAGNodes.h) and determine which operations the target natively supports. For operations that do not have native support, add a callback to the constructor for the XXXTargetLowering class, so the instruction selection process knows what to do. The TargetLowering class callback methods (declared in llvm/Target/TargetLowering.h) are:
Note: on older releases, setLoadXAction is used instead of setLoadExtAction. Also, on older releases, setCondCodeAction may not be supported. Examine your release to see what methods are specifically supported.
These callbacks are used to determine that an operation does or does not work with a specified type (or types). And in all cases, the third parameter is a LegalAction type enum value: Promote, Expand, Custom, or Legal. SparcISelLowering.cpp contains examples of all four LegalAction values.
For an operation without native support for a given type, the specified type may be promoted to a larger type that is supported. For example, SPARC does not support a sign-extending load for Boolean values (i1 type), so in SparcISelLowering.cpp the third parameter below, Promote, changes i1 type values to a large type before loading.
setLoadExtAction(ISD::SEXTLOAD, MVT::i1, Promote);
For a type without native support, a value may need to be broken down further, rather than promoted. For an operation without native support, a combination of other operations may be used to similar effect. In SPARC, the floating-point sine and cosine trig operations are supported by expansion to other operations, as indicated by the third parameter, Expand, to setOperationAction:
setOperationAction(ISD::FSIN, MVT::f32, Expand); setOperationAction(ISD::FCOS, MVT::f32, Expand);
For some operations, simple type promotion or operation expansion may be insufficient. In some cases, a special intrinsic function must be implemented.
For example, a constant value may require special treatment, or an operation may require spilling and restoring registers in the stack and working with register allocators.
As seen in SparcISelLowering.cpp code below, to perform a type conversion from a floating point value to a signed integer, first the setOperationAction should be called with Custom as the third parameter:
setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
In the LowerOperation method, for each Custom operation, a case statement should be added to indicate what function to call. In the following code, an FP_TO_SINT opcode will call the LowerFP_TO_SINT method:
SDValue SparcTargetLowering::LowerOperation( SDValue Op, SelectionDAG &DAG) { switch (Op.getOpcode()) { case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG); ... } }
Finally, the LowerFP_TO_SINT method is implemented, using an FP register to convert the floating-point value to an integer.
static SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG) { assert(Op.getValueType() == MVT::i32); Op = DAG.getNode(SPISD::FTOI, MVT::f32, Op.getOperand(0)); return DAG.getNode(ISD::BIT_CONVERT, MVT::i32, Op); }
The Legal LegalizeAction enum value simply indicates that an operation is natively supported. Legal represents the default condition, so it is rarely used. In SparcISelLowering.cpp, the action for CTPOP (an operation to count the bits set in an integer) is natively supported only for SPARC v9. The following code enables the Expand conversion technique for non-v9 SPARC implementations.
setOperationAction(ISD::CTPOP, MVT::i32, Expand); ... if (TM.getSubtarget<SparcSubtarget>().isV9()) setOperationAction(ISD::CTPOP, MVT::i32, Legal); case ISD::SETULT: return SPCC::ICC_CS; case ISD::SETULE: return SPCC::ICC_LEU; case ISD::SETUGT: return SPCC::ICC_GU; case ISD::SETUGE: return SPCC::ICC_CC; } }
To support target-specific calling conventions, XXXGenCallingConv.td uses interfaces (such as CCIfType and CCAssignToReg) that are defined in lib/Target/TargetCallingConv.td. TableGen can take the target descriptor file XXXGenCallingConv.td and generate the header file XXXGenCallingConv.inc, which is typically included in XXXISelLowering.cpp. You can use the interfaces in TargetCallingConv.td to specify:
The following example demonstrates the use of the CCIfType and CCAssignToReg interfaces. If the CCIfType predicate is true (that is, if the current argument is of type f32 or f64), then the action is performed. In this case, the CCAssignToReg action assigns the argument value to the first available register: either R0 or R1.
CCIfType<[f32,f64], CCAssignToReg<[R0, R1]>>
SparcCallingConv.td contains definitions for a target-specific return-value calling convention (RetCC_Sparc32) and a basic 32-bit C calling convention (CC_Sparc32). The definition of RetCC_Sparc32 (shown below) indicates which registers are used for specified scalar return types. A single-precision float is returned to register F0, and a double-precision float goes to register D0. A 32-bit integer is returned in register I0 or I1.
def RetCC_Sparc32 : CallingConv<[ CCIfType<[i32], CCAssignToReg<[I0, I1]>>, CCIfType<[f32], CCAssignToReg<[F0]>>, CCIfType<[f64], CCAssignToReg<[D0]>> ]>;
The definition of CC_Sparc32 in SparcCallingConv.td introduces CCAssignToStack, which assigns the value to a stack slot with the specified size and alignment. In the example below, the first parameter, 4, indicates the size of the slot, and the second parameter, also 4, indicates the stack alignment along 4-byte units. (Special cases: if size is zero, then the ABI size is used; if alignment is zero, then the ABI alignment is used.)
def CC_Sparc32 : CallingConv<[ // All arguments get passed in integer registers if there is space. CCIfType<[i32, f32, f64], CCAssignToReg<[I0, I1, I2, I3, I4, I5]>>, CCAssignToStack<4, 4> ]>;
CCDelegateTo is another commonly used interface, which tries to find a specified sub-calling convention and, if a match is found, it is invoked. In the following example (in X86CallingConv.td), the definition of RetCC_X86_32_C ends with CCDelegateTo. After the current value is assigned to the register ST0 or ST1, the RetCC_X86Common is invoked.
def RetCC_X86_32_C : CallingConv<[ CCIfType<[f32], CCAssignToReg<[ST0, ST1]>>, CCIfType<[f64], CCAssignToReg<[ST0, ST1]>>, CCDelegateTo<RetCC_X86Common> ]>;
CCIfCC is an interface that attempts to match the given name to the current calling convention. If the name identifies the current calling convention, then a specified action is invoked. In the following example (in X86CallingConv.td), if the Fast calling convention is in use, then RetCC_X86_32_Fast is invoked. If the SSECall calling convention is in use, then RetCC_X86_32_SSE is invoked.
def RetCC_X86_32 : CallingConv<[ CCIfCC<"CallingConv::Fast", CCDelegateTo<RetCC_X86_32_Fast>>, CCIfCC<"CallingConv::X86_SSECall", CCDelegateTo<RetCC_X86_32_SSE>>, CCDelegateTo<RetCC_X86_32_C> ]>;
Other calling convention interfaces include:
During the code emission stage, the code generator may utilize an LLVM pass to produce assembly output. To do this, you want to implement the code for a printer that converts LLVM IR to a GAS-format assembly language for your target machine, using the following steps:
The code in XXXTargetAsmInfo.h is usually a trivial declaration of the XXXTargetAsmInfo class for use in XXXTargetAsmInfo.cpp. Similarly, XXXTargetAsmInfo.cpp usually has a few declarations of XXXTargetAsmInfo replacement values that override the default values in TargetAsmInfo.cpp. For example in SparcTargetAsmInfo.cpp,
SparcTargetAsmInfo::SparcTargetAsmInfo(const SparcTargetMachine &TM) { Data16bitsDirective = "\t.half\t"; Data32bitsDirective = "\t.word\t"; Data64bitsDirective = 0; // .xword is only supported by V9. ZeroDirective = "\t.skip\t"; CommentString = "!"; ConstantPoolSection = "\t.section \".rodata\",#alloc\n"; }
The X86 assembly printer implementation (X86TargetAsmInfo) is an example where the target specific TargetAsmInfo class uses overridden methods: ExpandInlineAsm and PreferredEHDataFormat.
A target-specific implementation of AsmPrinter is written in XXXAsmPrinter.cpp, which implements the AsmPrinter class that converts the LLVM to printable assembly. The implementation must include the following headers that have declarations for the AsmPrinter and MachineFunctionPass classes. The MachineFunctionPass is a subclass of FunctionPass.
#include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineFunctionPass.h"
As a FunctionPass, AsmPrinter first calls doInitialization to set up the AsmPrinter. In SparcAsmPrinter, a Mangler object is instantiated to process variable names.
In XXXAsmPrinter.cpp, the runOnMachineFunction method (declared in MachineFunctionPass) must be implemented for XXXAsmPrinter. In MachineFunctionPass, the runOnFunction method invokes runOnMachineFunction. Target-specific implementations of runOnMachineFunction differ, but generally do the following to process each machine function:
The XXXAsmPrinter implementation must also include the code generated by TableGen that is output in the XXXGenAsmWriter.inc file. The code in XXXGenAsmWriter.inc contains an implementation of the printInstruction method that may call these methods:
The implementations of printDeclare, printImplicitDef, printInlineAsm, and printLabel in AsmPrinter.cpp are generally adequate for printing assembly and do not need to be overridden. (printBasicBlockLabel is another method that is implemented in AsmPrinter.cpp that may be directly used in an implementation of XXXAsmPrinter.)
The printOperand method is implemented with a long switch/case statement for the type of operand: register, immediate, basic block, external symbol, global address, constant pool index, or jump table index. For an instruction with a memory address operand, the printMemOperand method should be implemented to generate the proper output. Similarly, printCCOperand should be used to print a conditional operand.
doFinalization should be overridden in XXXAsmPrinter, and it should be called to shut down the assembly printer. During doFinalization, global variables and constants are printed to output.
Subtarget support is used to inform the code generation process of instruction set variations for a given chip set. For example, the LLVM SPARC implementation provided covers three major versions of the SPARC microprocessor architecture: Version 8 (V8, which is a 32-bit architecture), Version 9 (V9, a 64-bit architecture), and the UltraSPARC architecture. V8 has 16 double-precision floating-point registers that are also usable as either 32 single-precision or 8 quad-precision registers. V8 is also purely big-endian. V9 has 32 double-precision floating-point registers that are also usable as 16 quad-precision registers, but cannot be used as single-precision registers. The UltraSPARC architecture combines V9 with UltraSPARC Visual Instruction Set extensions.
If subtarget support is needed, you should implement a target-specific XXXSubtarget class for your architecture. This class should process the command-line options –mcpu= and –mattr=
TableGen uses definitions in the Target.td and Sparc.td files to generate code in SparcGenSubtarget.inc. In Target.td, shown below, the SubtargetFeature interface is defined. The first 4 string parameters of the SubtargetFeature interface are a feature name, an attribute set by the feature, the value of the attribute, and a description of the feature. (The fifth parameter is a list of features whose presence is implied, and its default value is an empty array.)
class SubtargetFeature<string n, string a, string v, string d, list<SubtargetFeature> i = []> { string Name = n; string Attribute = a; string Value = v; string Desc = d; list<SubtargetFeature> Implies = i; }
In the Sparc.td file, the SubtargetFeature is used to define the following features.
def FeatureV9 : SubtargetFeature<"v9", "IsV9", "true", "Enable SPARC-V9 instructions">; def FeatureV8Deprecated : SubtargetFeature<"deprecated-v8", "V8DeprecatedInsts", "true", "Enable deprecated V8 instructions in V9 mode">; def FeatureVIS : SubtargetFeature<"vis", "IsVIS", "true", "Enable UltraSPARC Visual Instruction Set extensions">;
Elsewhere in Sparc.td, the Proc class is defined and then is used to define particular SPARC processor subtypes that may have the previously described features.
class Proc<string Name, list<SubtargetFeature> Features> : Processor<Name, NoItineraries, Features>; def : Proc<"generic", []>; def : Proc<"v8", []>; def : Proc<"supersparc", []>; def : Proc<"sparclite", []>; def : Proc<"f934", []>; def : Proc<"hypersparc", []>; def : Proc<"sparclite86x", []>; def : Proc<"sparclet", []>; def : Proc<"tsc701", []>; def : Proc<"v9", [FeatureV9]>; def : Proc<"ultrasparc", [FeatureV9, FeatureV8Deprecated]>; def : Proc<"ultrasparc3", [FeatureV9, FeatureV8Deprecated]>; def : Proc<"ultrasparc3-vis", [FeatureV9, FeatureV8Deprecated, FeatureVIS]>;
From Target.td and Sparc.td files, the resulting SparcGenSubtarget.inc specifies enum values to identify the features, arrays of constants to represent the CPU features and CPU subtypes, and the ParseSubtargetFeatures method that parses the features string that sets specified subtarget options. The generated SparcGenSubtarget.inc file should be included in the SparcSubtarget.cpp. The target-specific implementation of the XXXSubtarget method should follow this pseudocode:
XXXSubtarget::XXXSubtarget(const Module &M, const std::string &FS) { // Set the default features // Determine default and user specified characteristics of the CPU // Call ParseSubtargetFeatures(FS, CPU) to parse the features string // Perform any additional operations }
The implementation of a target machine optionally includes a Just-In-Time (JIT) code generator that emits machine code and auxiliary structures as binary output that can be written directly to memory. To do this, implement JIT code generation by performing the following steps:
There are several different approaches to writing the JIT support code. For instance, TableGen and target descriptor files may be used for creating a JIT code generator, but are not mandatory. For the Alpha and PowerPC target machines, TableGen is used to generate XXXGenCodeEmitter.inc, which contains the binary coding of machine instructions and the getBinaryCodeForInstr method to access those codes. Other JIT implementations do not.
Both XXXJITInfo.cpp and XXXCodeEmitter.cpp must include the llvm/CodeGen/MachineCodeEmitter.h header file that defines the MachineCodeEmitter class containing code for several callback functions that write data (in bytes, words, strings, etc.) to the output stream.
In XXXCodeEmitter.cpp, a target-specific of the Emitter class is implemented as a function pass (subclass of MachineFunctionPass). The target-specific implementation of runOnMachineFunction (invoked by runOnFunction in MachineFunctionPass) iterates through the MachineBasicBlock calls emitInstruction to process each instruction and emit binary code. emitInstruction is largely implemented with case statements on the instruction types defined in XXXInstrInfo.h. For example, in X86CodeEmitter.cpp, the emitInstruction method is built around the following switch/case statements:
switch (Desc->TSFlags & X86::FormMask) { case X86II::Pseudo: // for not yet implemented instructions ... // or pseudo-instructions break; case X86II::RawFrm: // for instructions with a fixed opcode value ... break; case X86II::AddRegFrm: // for instructions that have one register operand ... // added to their opcode break; case X86II::MRMDestReg:// for instructions that use the Mod/RM byte ... // to specify a destination (register) break; case X86II::MRMDestMem:// for instructions that use the Mod/RM byte ... // to specify a destination (memory) break; case X86II::MRMSrcReg: // for instructions that use the Mod/RM byte ... // to specify a source (register) break; case X86II::MRMSrcMem: // for instructions that use the Mod/RM byte ... // to specify a source (memory) break; case X86II::MRM0r: case X86II::MRM1r: // for instructions that operate on case X86II::MRM2r: case X86II::MRM3r: // a REGISTER r/m operand and case X86II::MRM4r: case X86II::MRM5r: // use the Mod/RM byte and a field case X86II::MRM6r: case X86II::MRM7r: // to hold extended opcode data ... break; case X86II::MRM0m: case X86II::MRM1m: // for instructions that operate on case X86II::MRM2m: case X86II::MRM3m: // a MEMORY r/m operand and case X86II::MRM4m: case X86II::MRM5m: // use the Mod/RM byte and a field case X86II::MRM6m: case X86II::MRM7m: // to hold extended opcode data ... break; case X86II::MRMInitReg: // for instructions whose source and ... // destination are the same register break; }
The implementations of these case statements often first emit the opcode and then get the operand(s). Then depending upon the operand, helper methods may be called to process the operand(s). For example, in X86CodeEmitter.cpp, for the X86II::AddRegFrm case, the first data emitted (by emitByte) is the opcode added to the register operand. Then an object representing the machine operand, MO1, is extracted. The helper methods such as isImmediate, isGlobalAddress, isExternalSymbol, isConstantPoolIndex, and isJumpTableIndex determine the operand type. (X86CodeEmitter.cpp also has private methods such as emitConstant, emitGlobalAddress, emitExternalSymbolAddress, emitConstPoolAddress, and emitJumpTableAddress that emit the data into the output stream.)
case X86II::AddRegFrm: MCE.emitByte(BaseOpcode + getX86RegNum(MI.getOperand(CurOp++).getReg())); if (CurOp != NumOps) { const MachineOperand &MO1 = MI.getOperand(CurOp++); unsigned Size = X86InstrInfo::sizeOfImm(Desc); if (MO1.isImmediate()) emitConstant(MO1.getImm(), Size); else { unsigned rt = Is64BitMode ? X86::reloc_pcrel_word : (IsPIC ? X86::reloc_picrel_word : X86::reloc_absolute_word); if (Opcode == X86::MOV64ri) rt = X86::reloc_absolute_dword; // FIXME: add X86II flag? if (MO1.isGlobalAddress()) { bool NeedStub = isa<Function>(MO1.getGlobal()); bool isLazy = gvNeedsLazyPtr(MO1.getGlobal()); emitGlobalAddress(MO1.getGlobal(), rt, MO1.getOffset(), 0, NeedStub, isLazy); } else if (MO1.isExternalSymbol()) emitExternalSymbolAddress(MO1.getSymbolName(), rt); else if (MO1.isConstantPoolIndex()) emitConstPoolAddress(MO1.getIndex(), rt); else if (MO1.isJumpTableIndex()) emitJumpTableAddress(MO1.getIndex(), rt); } } break;
In the previous example, XXXCodeEmitter.cpp uses the variable rt, which is a RelocationType enum that may be used to relocate addresses (for example, a global address with a PIC base offset). The RelocationType enum for that target is defined in the short target-specific XXXRelocations.h file. The RelocationType is used by the relocate method defined in XXXJITInfo.cpp to rewrite addresses for referenced global symbols.
For example, X86Relocations.h specifies the following relocation types for the X86 addresses. In all four cases, the relocated value is added to the value already in memory. For reloc_pcrel_word and reloc_picrel_word, there is an additional initial adjustment.
enum RelocationType { reloc_pcrel_word = 0, // add reloc value after adjusting for the PC loc reloc_picrel_word = 1, // add reloc value after adjusting for the PIC base reloc_absolute_word = 2, // absolute relocation; no additional adjustment reloc_absolute_dword = 3 // absolute relocation; no additional adjustment };
XXXJITInfo.cpp implements the JIT interfaces for target-specific code-generation activities, such as emitting machine code and stubs. At minimum, a target-specific version of XXXJITInfo implements the following:
getLazyResolverFunction is generally trivial to implement. It makes the incoming parameter as the global JITCompilerFunction and returns the callback function that will be used a function wrapper. For the Alpha target (in AlphaJITInfo.cpp), the getLazyResolverFunction implementation is simply:
TargetJITInfo::LazyResolverFn AlphaJITInfo::getLazyResolverFunction( JITCompilerFn F) { JITCompilerFunction = F; return AlphaCompilationCallback; }
For the X86 target, the getLazyResolverFunction implementation is a little more complication, because it returns a different callback function for processors with SSE instructions and XMM registers.
The callback function initially saves and later restores the callee register values, incoming arguments, and frame and return address. The callback function needs low-level access to the registers or stack, so it is typically implemented with assembler.


Some things I’ve been involved in
Conjure - 2023
I submitted several pull requests that have been accepted and merged into Conjure. The PRs were small improvements for various programming language clients supported by Conjure. I also try to help others on Conjure's Discord site.
Conjure provides interactive evaluation of various languages in the Neovim editor. Originally developed for Clojure, it also supports other Lisp languages like Fennel, Racket, Scheme, Guile, Common Lisp and Janet. Some non-Lisp languages are also supported like Julia, Rust, Lua, and Python.
I made some notes about sending code blocks to a subprocess running a REPL (interactive program) for a programing language.
I'm enjoying starting to use Fennel for Neovim stuff. I wrote a quick post about this experience.
Keyboard Automated Design (KAD) - 2022
I submitted a pull request that has been accepted and merged into kad
. This
fix is used to generate EPS files. I use kad
to generate EPS files to get
laser cut switch plates from Ponoko to build
hand-wired mechanical keyboards for computers.
Parallel copy and checksum - 2019
While doing system administration work for the Information Technology Services department at the University of Hawaii, the disk arrays were upgraded several times and virtualized disk volumes were often resized. Frequently files needed to be copied from one virtualized volume to another due to the peculiarities of the disk arrays, volume management software, etc. These activies were often performed during a scheduled outage.
To ensure that we didn't waste time during the outages, I wrote a Go program,
pcopy
, to copy a lot of files from one directory to another. It was also
crucial to ensure the integrity of the data so there's a companion Go program,
psha1sum
, to generate the SHA1 checksums of the files in the destination
directory. Then the checksums generated by the copy program can be compared to
verify that no data has been mangled before proceeding with the next steps of
the data migration.
Kaimuki YMCA - 2018
Faced with the challenges of recruiting and retaining employees, the Kaimuki YMCA wanted to take advantage of the Google for Jobs service so that their job postings would have higer visibility for job seekers. Not having the technical staff familiar with the structured data that could be added to the job posting pages, I created a web page to make it easy to create the structured data to add to their website so that Google searches for jobs will put their job openings at the top of searches (see https://jobs.google.com/about/). Demo it here.
3rd Place in the Hawaii Machine Learning Meetup Challenge - 2018
The organizers of the Hawaii Machine Learning Meetup group put on a friendly competition to predict the amount of items that would purchased based on real retail store sales data. My team, BFBI, took 3rd place out of a field of ten.
Code for Hawaii - 2016
I contributed work that helped bring the UIPA website to life. UIPA stands for Uniform Information Practices Act. The public can make freedom of information requests to Hawaii state and county departments. The website was deployed in 2016.
The first Hawaii Annual Code Challenge HACC 2016
I was on the iDelve team and Team Fossil.
Team Fossil did a data visualization of campaign contributions by industry groups. The written submission can be found at https://devpost.com/software/campaign-contributions-by-industry-segment and the visualization can be found at https://hacc2016.github.io/teamfossil/visualization/.


--- layout: layout title: Downloads menu: downloads redirect_from: - /en/downloads - /en/olddownloads - /en/nightlies - /olddownloads - /nightlies ---
The latest stable version of DMDirc is {{ site.versions.stable }}. DMDirc is available to download as both a platform-specific installer and a platform independent jar file:
DMDirc-{{ site.versions.stable }}.exe
For Windows Vista, 7 and 8
DMDirc-{{ site.versions.stable }}.deb
For Debian, Ubuntu, etc
DMDirc-{{ site.versions.stable }}.rpm
For Red Hat, Fedora, etc
DMDirc-{{ site.versions.stable }}.dmg
For Mac OS X
DMDirc-{{ site.versions.stable }}.jar
For advanced users, on any platform that supports Java
Users of Debian-based distros can also use our apt repository to stay up to date automatically:
sudo wget http://www.dmdirc.com/apt/dmdirc.list -O /etc/apt/sources.list.d/dmdirc.list wget -qO- http://www.dmdirc.com/apt/dmdirc.gpg.key | sudo apt-key add - sudo apt-get update sudo apt-get install dmdirc


We recommend that you load libraries from the CDN via HTTPS, even if your own website only uses HTTP.
Nowadays, performance is fast, and caching works just the same. The CDN's files are served with CORS
and Timing-Allow headers and allowed to be cached for 1 year.
We recommend that you load libraries from the CDN via HTTPS, even if your own website only uses HTTP.
Nowadays, performance is fast, and caching works just the same. The CDN's files are served with CORS
and Timing-Allow headers and allowed to be cached for 1 year.
and Timing-Allow headers and allowed to be cached for 1 year.
Columna1
We recommend that you load libraries from the CDN via HTTPS, even if your own website only uses HTTP.
Nowadays, performance is fast, and caching works just the same. The CDN's files are served with CORS
and Timing-Allow headers and allowed to be cached for 1 year.
Columna2
We recommend that you load libraries from the CDN via HTTPS, even if your own website only uses HTTP.
Nowadays, performance is fast, and caching works just the same. The CDN's files are served with CORS
and Timing-Allow headers and allowed to be cached for 1 year.
Columna3
We recommend that you load libraries from the CDN via HTTPS, even if your own website only uses HTTP.
Nowadays, performance is fast, and caching works just the same. The CDN's files are served with CORS
and Timing-Allow headers and allowed to be cached for 1 year.
Columna4
We recommend that you load libraries from the CDN via HTTPS, even if your own website only uses HTTP.
Nowadays, performance is fast, and caching works just the same. The CDN's files are served with CORS
and Timing-Allow headers and allowed to be cached for 1 year.


We'll forward your issue to your credit card company, give you a tracking number, and keep you updated on the status of your complaint.
Submit a credit card complaint
The CARD Act is often called the Credit Cardholders Bill of Rights. President Obama signed the bill into law in May 2009. Many of the most significant provisions of the law took effect in February 2010.
Read more about the Credit CARD Act
Find guides, your rights related to your credit score, and your credit card protections.


msfHub
Edit Users
Profile
Modules
Header
Reports
Logout
Your token has expired, please re-login
Please Login
Username
Username is required.
Password
Password is required.
Login
Modules
Button
Source available on
GitHub