SlideShare a Scribd company logo
Min-Yih “Min” Hsu @ LLVM Dev Meeting 2021
Handling inline assembly 

in Clang and LLVM
about:me
“Min” Hsu
• Computer Science PhD Candidate in
University of California, Irvine

• Code owner of M68k LLVM backend

• Author of book “LLVM Techniques,
Tips and Best Practices” (2021)
2
How Inline Assembly is
Processed in Clang & LLVM
3
Inline Assembly
4
Introduction to inline assembly
5
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
5
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
5
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


foo:


pushq %rbp


movq %rsp, %rbp


...


testb $1, -9(%rbp)


je LBB0_2


## InlineAsm Start


movl %eax, %ebx


addl %ebx, %esi


## InlineAsm End


jmp LBB0_3


LBB0_2:


movl -8(%rbp), %eax


addl $87, %eax


movl %eax, -8(%rbp)


LBB0_3:


popq %rbp


retq
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
5
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


foo:


pushq %rbp


movq %rsp, %rbp


...


testb $1, -9(%rbp)


je LBB0_2


## InlineAsm Start


movl %eax, %ebx


addl %ebx, %esi


## InlineAsm End


jmp LBB0_3


LBB0_2:


movl -8(%rbp), %eax


addl $87, %eax


movl %eax, -8(%rbp)


LBB0_3:


popq %rbp


retq
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Why use inline assembly?
6
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Why use inline assembly?
6
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


Performance critical code
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Why use inline assembly?
6
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


Performance critical code
Low-level code

e.g. Kernel, firmware
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Why use inline assembly?
6
void foo(...) {


int sum = 0;


bool flag = ...;


if (flag)


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);


else


sum += 87;


}


Performance critical code
Low-level code

e.g. Kernel, firmware
Compiler optimizations “barrier”
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
7
asm (“movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
7
asm (“movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);
Assembly code (template)
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
7
asm (“movl %%eax, %%ebxn"


"addl %%ebx, %%esi" :::);
Assembly code (template)
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Output operands
8
int out_var;


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %0"


: "=r"(out_var) ::);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Output operands
8
int out_var;


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %0"


: "=r"(out_var) ::);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Output operands
8
int out_var;


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %0"


: "=r"(out_var) ::);
Operand constraints
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Operands constraints
9
int out_var;


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %0"


: "=r"(out_var) ::);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Operands constraints
9
int out_var;


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %0"


: "=r"(out_var) ::);
* x86_64 assembly w/ AT&T syntax
## InlineAsm Start


movl %eax, %ebx


addl %ebx, %esi


## InlineAsm End
Introduction to inline assembly
Operands constraints
9
int out_var;


asm ("movl %%eax, %%ebxn"


"addl %%ebx, %0"


: "=r"(out_var) ::);
* x86_64 assembly w/ AT&T syntax
## InlineAsm Start


movl %eax, %ebx


addl %ebx, %esi


## InlineAsm End
## InlineAsm Start


movl %eax, %ebx


addl %ebx, -8(%ebp)


## InlineAsm End
Operand constraints
10
Operand constraints
10
• ‘r’ : General-purpose register operand

• ‘i’ : Immediate integer operand

• ‘m’ : Memory operand w/ arbitrary addressing mode
Target-independent Constraints
Operand constraints
10
• ‘r’ : General-purpose register operand

• ‘i’ : Immediate integer operand

• ‘m’ : Memory operand w/ arbitrary addressing mode
Target-independent Constraints
• ‘a’ : AL / AH / EAX / RAX

• ‘I’ : Integer constant in the range of [0, 31]

• ‘N’ : Unsigned 8-bit integer constant
X86 Constraints
Operand constraints
10
• ‘r’ : General-purpose register operand

• ‘i’ : Immediate integer operand

• ‘m’ : Memory operand w/ arbitrary addressing mode
Target-independent Constraints
• ‘a’ : AL / AH / EAX / RAX

• ‘I’ : Integer constant in the range of [0, 31]

• ‘N’ : Unsigned 8-bit integer constant
X86 Constraints
• ‘J’ : 16-bit signed integer constant

• “Ci” : Constant integers

• “Cj” : Constant signed integers that do NOT
fi
t in 16 bits
M68k Constraints
Operand constraints
10
• ‘r’ : General-purpose register operand

• ‘i’ : Immediate integer operand

• ‘m’ : Memory operand w/ arbitrary addressing mode
Constraint Modifers
Target-independent Constraints
• ‘=‘ : This is an output operand

• ‘+’ : This is an input / output operand
• ‘a’ : AL / AH / EAX / RAX

• ‘I’ : Integer constant in the range of [0, 31]

• ‘N’ : Unsigned 8-bit integer constant
X86 Constraints
• ‘J’ : 16-bit signed integer constant

• “Ci” : Constant integers

• “Cj” : Constant signed integers that do NOT
fi
t in 16 bits
M68k Constraints
Introduction to inline assembly
Input operands
11
int out_var, in_var;


asm ("movl %1, %%ebxn"


"addl %%ebx, %0"


: “=r"(out_var)


: “r”(in_var) :);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Input operands
11
int out_var, in_var;


asm ("movl %1, %%ebxn"


"addl %%ebx, %0"


: “=r"(out_var)


: “r”(in_var) :);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Input operands
11
int out_var, in_var;


asm ("movl %1, %%ebxn"


"addl %%ebx, %0"


: “=r"(out_var)


: “r”(in_var) :);
Operand constraints
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Clobber operands
12
int out_var, in_var;


asm ("movl %1, %%ebxn"


"addl %%ebx, %0"


: “=r"(out_var)


: “r”(in_var)


: “ebx”);
* x86_64 assembly w/ AT&T syntax
Introduction to inline assembly
Clobber operands
12
int out_var, in_var;


asm ("movl %1, %%ebxn"


"addl %%ebx, %0"


: “=r"(out_var)


: “r”(in_var)


: “ebx”);
* x86_64 assembly w/ AT&T syntax
For more inline assembly syntax…
13
https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
Handling inline assembly in Clang & LLVM
Background
14
Handling inline assembly in Clang & LLVM
Background
• Most parts of an inline assembly string are simply copied into the
fi
nal
assembly
fi
le
14
Handling inline assembly in Clang & LLVM
Background
• Most parts of an inline assembly string are simply copied into the
fi
nal
assembly
fi
le
• LLVM needs to “glue” inline assembly operands with the surrounding code
14
Handling inline assembly in Clang & LLVM
Background
• Most parts of an inline assembly string are simply copied into the
fi
nal
assembly
fi
le
• LLVM needs to “glue” inline assembly operands with the surrounding code
• Lots of target-speci
fi
c logics

• In both Clang and the backend
14
Handling inline assembly in Clang & LLVM
Background
• Most parts of an inline assembly string are simply copied into the
fi
nal
assembly
fi
le
• LLVM needs to “glue” inline assembly operands with the surrounding code
• Lots of target-speci
fi
c logics

• In both Clang and the backend
• Target-speci
fi
c callbacks are scattered in the codebase

• Documentation for this part is a little…shy
14
Goals
15
Goals
Learning inline assembly workflow in Clang / LLVM
15
Goals
Learning inline assembly workflow in Clang / LLVM
A simple guide for backend developers to add inline assembly support
15
Outline of target-specific logics in each stage
16
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
Outline of target-specific logics in each stage
16
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
• Simple validation on operand constraints

• Converting constraints
Outline of target-specific logics in each stage
16
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
• Simple validation on operand constraints

• Converting constraints
• Classifying constraints

• Constraint validations

• Lowering the operands
Outline of target-specific logics in each stage
16
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
• Simple validation on operand constraints

• Converting constraints
• Classifying constraints

• Constraint validations

• Lowering the operands
Print out di
ff
erent types of operands
Outline of target-specific logics in each stage
17
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
• Simple validation on operand constraints

• Converting constraints
• Classifying constraints

• Constraint validations

• Lowering the operands
Print out di
ff
erent types of operands
Operand constraint validations in Clang
18
bool TargetInfo::validateAsmConstraint(const char *&, ConstraintInfo &) const;
Operand constraint validations in Clang
18
bool TargetInfo::validateAsmConstraint(const char *&, ConstraintInfo &) const;
bool M68kTargetInfo::validateAsmConstraint(const char *&Name, ConstraintInfo &info) const {


switch (*Name) {


case 'a': // address register


info.setAllowsRegister();


return true;


}


…


}
Operand constraint validations in Clang
19
bool TargetInfo::validateAsmConstraint(const char *&, ConstraintInfo &) const;
bool M68kTargetInfo::validateAsmConstraint(const char *&Name, ConstraintInfo &info) const {


switch (*Name) {


case 'a': // address register


info.setAllowsRegister();


return true;


case 'J': // constant signed 16-bit integer


info.setRequiresImmediate(std::numeric_limits<int16_t>::min(),


std::numeric_limits<int16_t>::max());


return true;


}


…


}
Operand constraint validations in Clang
Limitation on immediate value validations
20
void foo() {


int32_t x;


asm ("move.l %0, %%d1" : : "J" (x));


}
* M68k assembly w/ Motorola syntax
Operand constraint validations in Clang
Limitation on immediate value validations
20
void foo() {


int32_t x;


asm ("move.l %0, %%d1" : : "J" (x));


}
Constant signed 16-bit integer
* M68k assembly w/ Motorola syntax
Operand constraint validations in Clang
Limitation on immediate value validations
20
void foo() {


int32_t x;


asm ("move.l %0, %%d1" : : "J" (x));


}
$ clang -target m68k -fsyntax-only foo.c


# No error


$ clang -target m68k -emit-llvm foo.c


# No error
Constant signed 16-bit integer
* M68k assembly w/ Motorola syntax
Operand constraint validations in Clang
Limitation on immediate value validations
20
void foo() {


int32_t x;


asm ("move.l %0, %%d1" : : "J" (x));


}
$ clang -target m68k -fsyntax-only foo.c


# No error


$ clang -target m68k -emit-llvm foo.c


# No error
Constant signed 16-bit integer
$ clang -target m68k -S foo.c


error: constraint 'J' expects an integer constant expression
* M68k assembly w/ Motorola syntax
Inline assembly in LLVM IR
21
void foo() {


const int x = 87;


asm ("move.l %0, %%d1" : : "Ci" (x) : "d1");


}
C/C++
* M68k assembly w/ Motorola syntax
Inline assembly in LLVM IR
21
void foo() {


const int x = 87;


asm ("move.l %0, %%d1" : : "Ci" (x) : "d1");


}
C/C++
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
LLVM IR
* M68k assembly w/ Motorola syntax
Inline assembly in LLVM IR
21
void foo() {


const int x = 87;


asm ("move.l %0, %%d1" : : "Ci" (x) : "d1");


}
C/C++
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
LLVM IR
* M68k assembly w/ Motorola syntax
Inline assembly in LLVM IR
21
void foo() {


const int x = 87;


asm ("move.l %0, %%d1" : : "Ci" (x) : "d1");


}
C/C++
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
LLVM IR
* M68k assembly w/ Motorola syntax
Inline assembly in LLVM IR
21
void foo() {


const int x = 87;


asm ("move.l %0, %%d1" : : "Ci" (x) : "d1");


}
C/C++
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
LLVM IR
* M68k assembly w/ Motorola syntax
Inline assembly in LLVM IR
21
void foo() {


const int x = 87;


asm ("move.l %0, %%d1" : : "Ci" (x) : "d1");


}
C/C++
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
LLVM IR
* M68k assembly w/ Motorola syntax
Outline of target-specific logics in each stage
22
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
• Simple validation on operand constraints

• Converting constraints
• Classifying constraints

• Constraint validations

• Lowering the operands
Print out di
ff
erent types of operands
23
LLVM IR call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
23
LLVM IR
SelectionDAG
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
t2: ch,glue = inlineasm ... "move.l $0, %d1", ...,


TargetConstant:i32<87>, Register:i16 $d1
23
LLVM IR
SelectionDAG
Machine IR
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
t2: ch,glue = inlineasm ... "move.l $0, %d1", ...,


TargetConstant:i32<87>, Register:i16 $d1
23
LLVM IR
SelectionDAG
Machine IR
call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
t2: ch,glue = inlineasm ... "move.l $0, %d1", ...,


TargetConstant:i32<87>, Register:i16 $d1
Constraint classification
24
TargetLowering::ConstraintType


M68kTargetLowering::getConstraintType(StringRef Constraint) const;
Constraint classification
24
TargetLowering::ConstraintType


M68kTargetLowering::getConstraintType(StringRef Constraint) const;
Return:
Constraint classification
24
TargetLowering::ConstraintType


M68kTargetLowering::getConstraintType(StringRef Constraint) const;
• C_RegisterClass
Return:
Ex: ’r’
Constraint classification
24
TargetLowering::ConstraintType


M68kTargetLowering::getConstraintType(StringRef Constraint) const;
• C_RegisterClass
• C_Immediate
Return:
Ex: ’r’
Ex: ‘i’
Constraint classification
24
TargetLowering::ConstraintType


M68kTargetLowering::getConstraintType(StringRef Constraint) const;
• C_RegisterClass
• C_Immediate
• C_Memory
Return:
Ex: ’r’
Ex: ‘i’
Ex: ‘m’, ‘Q’ (AArch64)
Constraint classification
24
TargetLowering::ConstraintType


M68kTargetLowering::getConstraintType(StringRef Constraint) const;
• C_RegisterClass
• C_Immediate
• C_Memory
• C_Other
Return:
Ex: ’r’
Ex: ‘i’
Ex: ‘m’, ‘Q’ (AArch64)
Lowering operands
25
getConstraintType
Method in XXXTargetLowering
Method in XXXISelDAGToDAG
Will be invoked
Lowering operands
25
getConstraintType
getRegForInlineAsmConstraint
C_RegisterClass
Method in XXXTargetLowering
Method in XXXISelDAGToDAG
Will be invoked
Lowering operands
25
getConstraintType
getRegForInlineAsmConstraint
LowerAsmOperandForConstraint
C_RegisterClass
C_Immediate / C_Other
Method in XXXTargetLowering
Method in XXXISelDAGToDAG
Will be invoked
Lowering operands
25
getConstraintType
getRegForInlineAsmConstraint
getInlineAsmMemConstraint
LowerAsmOperandForConstraint
C_RegisterClass
C_Immediate / C_Other
C_Memory
Method in XXXTargetLowering
Method in XXXISelDAGToDAG
Will be invoked
Lowering operands
25
getConstraintType
getRegForInlineAsmConstraint
getInlineAsmMemConstraint
LowerAsmOperandForConstraint
SelectInlineAsmMemoryOperand
C_RegisterClass
C_Immediate / C_Other
C_Memory
Method in XXXTargetLowering
Method in XXXISelDAGToDAG
Will be invoked
Lowering register operands
26
std::pair<unsigned, const TargetRegisterClass *>


TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,


StringRef Constraint,


MVT VT) const;
Lowering register operands
26
std::pair<unsigned, const TargetRegisterClass *>


TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,


StringRef Constraint,


MVT VT) const;
A speci
fi
c register or 0 if not applicable
Lowering register operands
26
std::pair<unsigned, const TargetRegisterClass *>


TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,


StringRef Constraint,


MVT VT) const;
A speci
fi
c register or 0 if not applicable Valid register class to select from
Lowering register operands
M68k Example
27
std::pair<unsigned, const TargetRegisterClass *>


M68kTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *,


StringRef Constraint,


MVT VT) const {


switch (Constraint[0]) {


case 'a':


switch (VT.SimpleTy) {


case MVT::i16:


return std::make_pair(0U, &M68k::AR16RegClass);


}


}


}
Lowering register operands
M68k Example
27
std::pair<unsigned, const TargetRegisterClass *>


M68kTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *,


StringRef Constraint,


MVT VT) const {


switch (Constraint[0]) {


case 'a':


switch (VT.SimpleTy) {


case MVT::i16:


return std::make_pair(0U, &M68k::AR16RegClass);


}


}


}
Lowering register operands
X86 Example
28
std::pair<unsigned, const TargetRegisterClass *>


X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *,


StringRef Constraint,


MVT VT) const {


...


if (Constraint == "Yz") {


// First SSE register (%xmm0).


switch (VT.SimpleTy) {


case MVT::f32:


case MVT::i32:


return std::make_pair(X86::XMM0, &X86::FR32RegClass);


}


}


}
Lowering register operands
X86 Example
28
std::pair<unsigned, const TargetRegisterClass *>


X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *,


StringRef Constraint,


MVT VT) const {


...


if (Constraint == "Yz") {


// First SSE register (%xmm0).


switch (VT.SimpleTy) {


case MVT::f32:


case MVT::i32:


return std::make_pair(X86::XMM0, &X86::FR32RegClass);


}


}


}
Lowering immediate / other operands
29
void TargetLowering::


LowerAsmOperandForConstraint(SDValue Op,


std::string &Constraint,


std::vector<SDValue> &Ops,


SelectionDAG &DAG) const;
Lowering immediate / other operands
M68k Example
30
void M68kTargetLowering::LowerAsmOperandForConstraint(SDValue Op,


std::string &Constraint,


std::vector<SDValue> &Ops,


SelectionDAG &DAG) const {


switch (Constraint[0]) {


case 'J': { // constant signed 16-bit integer


}


}


}
Lowering immediate / other operands
M68k Example
31
void M68kTargetLowering::LowerAsmOperandForConstraint(SDValue Op,


std::string &Constraint,


std::vector<SDValue> &Ops,


SelectionDAG &DAG) const {


switch (Constraint[0]) {


case 'J': { // constant signed 16-bit integer


if (auto *C = dyn_cast<ConstantSDNode>(Op)) {


int64_t Val = C->getSExtValue();


}


}


}


}
Lowering immediate / other operands
M68k Example
32
void M68kTargetLowering::LowerAsmOperandForConstraint(SDValue Op,


std::string &Constraint,


std::vector<SDValue> &Ops,


SelectionDAG &DAG) const {


switch (Constraint[0]) {


case 'J': { // constant signed 16-bit integer


if (auto *C = dyn_cast<ConstantSDNode>(Op)) {


int64_t Val = C->getSExtValue();


if (isInt<16>(Val)) {


Ops.push_back(Op);


return;


}


}


}


}


}
Lowering memory operands
Memory constraint classi
fi
cation
33
unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const;
Lowering memory operands
Memory constraint classi
fi
cation
33
unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const;
Return:
Lowering memory operands
Memory constraint classi
fi
cation
33
unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const;
• InlineAsm::Constraint_m


• InlineAsm::Constraint_o


• InlineAsm::Constraint_v
Return:
Generic memory constraints
Lowering memory operands
Memory constraint classi
fi
cation
33
unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const;
• InlineAsm::Constraint_m


• InlineAsm::Constraint_o


• InlineAsm::Constraint_v
Return:
• InlineAsm::Constraint_A


• InlineAsm::Constraint_Q
Generic memory constraints
Target-speci
fi
c constraints!
Lowering memory operands
Memory constraint classi
fi
cation — RISCV Example
34
unsigned RISCVTargetLowering::


getInlineAsmMemConstraint(StringRef ConstraintCode) const {


switch (ConstraintCode[0]) {


case 'A':


return InlineAsm::Constraint_A;


...


}


...


}
Lowering memory operands
35
bool


SelectionDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,


unsigned ConstraintID,


std::vector<SDValue> &OutOps);
Lowering memory operands
RISCV Example
36
bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand(


const SDValue &Op, unsigned ConstraintID,


std::vector<SDValue> &OutOps) {


switch (ConstraintID) {


case InlineAsm::Constraint_A:


OutOps.push_back(Op);


return false;


default:


break;


}




return true;


}
Lowering memory operands
Complex addressing mode — X86 Example
37
bool X86DAGToDAGISel::


SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,


std::vector<SDValue> &OutOps) {


SDValue Op0, Op1, Op2, Op3, Op4;




switch (ConstraintID) {


case InlineAsm::Constraint_m: // memory


if (!selectAddr(nullptr, Op, Op0, Op1, Op2, Op3, Op4))


return true;


break;


}


OutOps.insert(OutOps.end(), {Op0, Op1, Op2, Op3, Op4});


return false;


}
Lowering memory operands
Complex addressing mode — X86 Example
37
bool X86DAGToDAGISel::


SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID,


std::vector<SDValue> &OutOps) {


SDValue Op0, Op1, Op2, Op3, Op4;




switch (ConstraintID) {


case InlineAsm::Constraint_m: // memory


if (!selectAddr(nullptr, Op, Op0, Op1, Op2, Op3, Op4))


return true;


break;


}


OutOps.insert(OutOps.end(), {Op0, Op1, Op2, Op3, Op4});


return false;


}
Outline of target-specific logics in each stage
38
Clang
Lowering
LLVM IR
Machine IR
AsmPrinter
• Simple validation on operand constraints

• Converting constraints
• Classifying constraints

• Constraint validations

• Lowering the operands
Print out di
ff
erent types of operands
39
Machine IR
INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
39
Machine IR
INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
39
Machine IR
INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
move.l #87, %d1
39
Machine IR
INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
move.l 87, %d1
move.l #87, %d1
Printing asm operands
40
bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,


const char *, raw_ostream &O);


bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,


const char *, raw_ostream &O);
Printing non-memory asm operands
M68k Example
41
void M68kAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,


raw_ostream &OS) {


const MachineOperand &MO = MI->getOperand(OpNum);


switch (MO.getType()) {


case MachineOperand::MO_Register:


OS << "%" << M68kInstPrinter::getRegisterName(MO.getReg());


break;


case MachineOperand::MO_Immediate:


OS << '#' << MO.getImm();


break;


...


}


}
Printing non-memory asm operands
M68k Example
41
void M68kAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,


raw_ostream &OS) {


const MachineOperand &MO = MI->getOperand(OpNum);


switch (MO.getType()) {


case MachineOperand::MO_Register:


OS << "%" << M68kInstPrinter::getRegisterName(MO.getReg());


break;


case MachineOperand::MO_Immediate:


OS << '#' << MO.getImm();


break;


...


}


}
Printing non-memory asm operands
M68k Example
41
void M68kAsmPrinter::printOperand(const MachineInstr *MI, int OpNum,


raw_ostream &OS) {


const MachineOperand &MO = MI->getOperand(OpNum);


switch (MO.getType()) {


case MachineOperand::MO_Register:


OS << "%" << M68kInstPrinter::getRegisterName(MO.getReg());


break;


case MachineOperand::MO_Immediate:


OS << '#' << MO.getImm();


break;


...


}


}
Epilogue
Advanced topics
Converting constraints in Clang

Asm dialects

Operand modifiers

Multi-alternative constraints

Constraint weights

Turn (simple) inline asm into LLVM code
43
Thank you!
44
GitHub: mshockwave

Email: minyihh@uci.edu 

25% book discount code: 25MINLLVM
Redeem:
Nov 15 ~ Nov 20, 2021
Appendix
Converting constraints in Clang
46
An operand constraint is assumed to have only a single character by default
Converting constraints in Clang
46
An operand constraint is assumed to have only a single character by default
Example: “Ci”
Converting constraints in Clang
46
An operand constraint is assumed to have only a single character by default
Example: “Ci” -> “^Ci”
Converting constraints in Clang
46
std::string


M68kTargetInfo::convertConstraint(const char *&Constraint) const override {


if (*Constraint == 'C')


// Two-character constraint; add "^" hint for later parsing


return std::string("^") + std::string(Constraint++, 2);


return std::string(1, *Constraint);


}
An operand constraint is assumed to have only a single character by default
Example: “Ci” -> “^Ci”
Operand constraint validations in Clang
Limitation on immediate value validations (cont’d)
47
bool M68kTargetInfo::validateAsmConstraint(const char *&Name, ConstraintInfo &info) const {


switch (*Name) {


…


case 'C':


++Name;


switch (*Name) {


case 'i': // constant integer


case 'j': // integer constant that doesn't fit in 16 bits


info.setRequiresImmediate();


return true;


}


break;


}


…


}

More Related Content

PDF
LLVM Register Allocation
PPTX
LLVM Backend Porting
PDF
Q2.12: Debugging with GDB
PDF
Instruction Combine in LLVM
PPTX
LLVM Instruction Selection
PDF
How mysql handles ORDER BY, GROUP BY, and DISTINCT
PDF
Session 9 advance_verification_features
PDF
Address/Thread/Memory Sanitizer
LLVM Register Allocation
LLVM Backend Porting
Q2.12: Debugging with GDB
Instruction Combine in LLVM
LLVM Instruction Selection
How mysql handles ORDER BY, GROUP BY, and DISTINCT
Session 9 advance_verification_features
Address/Thread/Memory Sanitizer

What's hot (20)

PDF
How A Compiler Works: GNU Toolchain
PDF
Binary exploitation - AIS3
PDF
Valgrind tutorial
PDF
Valgrind
PDF
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
PDF
A look into the sanitizer family (ASAN & UBSAN) by Akul Pillai
PDF
Challenges in Using UVM at SoC Level
PDF
Mavenの真実とウソ
PDF
規格書で読むC++11のスレッド
PDF
UVM Update: Register Package
PPT
Functions in C++
PPTX
冬のLock free祭り safe
PDF
Rust Is Safe. But Is It Fast?
PDF
GDB Rocks!
PDF
Process Management
PPT
Misra c rules
PDF
淺談探索 Linux 系統設計之道
PDF
/proc/irq/&lt;irq>/smp_affinity
PDF
Learn C Programming Language by Using GDB
PDF
containerdの概要と最近の機能
How A Compiler Works: GNU Toolchain
Binary exploitation - AIS3
Valgrind tutorial
Valgrind
constexpr関数はコンパイル時処理。これはいい。実行時が霞んで見える。cpuの嬌声が聞こえてきそうだ
A look into the sanitizer family (ASAN & UBSAN) by Akul Pillai
Challenges in Using UVM at SoC Level
Mavenの真実とウソ
規格書で読むC++11のスレッド
UVM Update: Register Package
Functions in C++
冬のLock free祭り safe
Rust Is Safe. But Is It Fast?
GDB Rocks!
Process Management
Misra c rules
淺談探索 Linux 系統設計之道
/proc/irq/&lt;irq>/smp_affinity
Learn C Programming Language by Using GDB
containerdの概要と最近の機能
Ad

Similar to Handling inline assembly in Clang and LLVM (20)

PPT
Al2ed chapter17
PPTX
Chapter_04_ARM_Assembly.pptx ARM ASSEMBLY CODE
PPTX
Chapter_04_ARM_Assembly ARM assembly language is the low-level programming.pptx
PPTX
Inline assembly language programs in c
ODP
The forgotten art of assembly
PPT
Assembly Langauge Assembly Langauge Assembly Langauge
PPTX
07 140430-ipp-languages used in llvm during compilation
PDF
Assembly language part I
PDF
Assembly language part I
PPTX
Introduction to ARM Systems-11-17-2012.pptx
PDF
hashdays 2011: Ange Albertini - Such a weird processor - messing with x86 opc...
PPTX
microprocessors and ARM Assembly Language
PDF
Module4.pdf ,...................................
PPTX
Coal (1)
PPTX
C++ and Assembly: Debugging and Reverse Engineering
PDF
LCU14 209- LLVM Linux
PPS
An introduction to Reverse Engineering
PDF
LAS16-501: Introduction to LLVM - Projects, Components, Integration, Internals
PPT
IS 139 Lecture 6
PPTX
Module 2 ARM CORTEX M3 Instruction Set and Programming
Al2ed chapter17
Chapter_04_ARM_Assembly.pptx ARM ASSEMBLY CODE
Chapter_04_ARM_Assembly ARM assembly language is the low-level programming.pptx
Inline assembly language programs in c
The forgotten art of assembly
Assembly Langauge Assembly Langauge Assembly Langauge
07 140430-ipp-languages used in llvm during compilation
Assembly language part I
Assembly language part I
Introduction to ARM Systems-11-17-2012.pptx
hashdays 2011: Ange Albertini - Such a weird processor - messing with x86 opc...
microprocessors and ARM Assembly Language
Module4.pdf ,...................................
Coal (1)
C++ and Assembly: Debugging and Reverse Engineering
LCU14 209- LLVM Linux
An introduction to Reverse Engineering
LAS16-501: Introduction to LLVM - Projects, Components, Integration, Internals
IS 139 Lecture 6
Module 2 ARM CORTEX M3 Instruction Set and Programming
Ad

More from Min-Yih Hsu (14)

PDF
Debug Information And Where They Come From
PDF
MCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
PDF
How to write a TableGen backend
PDF
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
PDF
[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...
PDF
Paper Study - Demand-Driven Computation of Interprocedural Data Flow
PDF
Paper Study - Incremental Data-Flow Analysis Algorithms by Ryder et al
PDF
Souper-Charging Peepholes with Target Machine Info
PDF
From V8 to Modern Compilers
PDF
Introduction to Khronos SYCL
PDF
Trace Scheduling
PDF
Polymer Start-Up (SITCON 2016)
PDF
War of Native Speed on Web (SITCON2016)
PDF
From Android NDK To AOSP
Debug Information And Where They Come From
MCA Daemon: Hybrid Throughput Analysis Beyond Basic Blocks
How to write a TableGen backend
[COSCUP 2021] LLVM Project: The Good, The Bad, and The Ugly
[TGSA Academic Friday] How To Train Your Dragon - Intro to Modern Compiler Te...
Paper Study - Demand-Driven Computation of Interprocedural Data Flow
Paper Study - Incremental Data-Flow Analysis Algorithms by Ryder et al
Souper-Charging Peepholes with Target Machine Info
From V8 to Modern Compilers
Introduction to Khronos SYCL
Trace Scheduling
Polymer Start-Up (SITCON 2016)
War of Native Speed on Web (SITCON2016)
From Android NDK To AOSP

Recently uploaded (20)

PDF
Wondershare Filmora 15 Crack With Activation Key [2025
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
wealthsignaloriginal-com-DS-text-... (1).pdf
PPTX
Reimagine Home Health with the Power of Agentic AI​
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PPTX
Introduction to Artificial Intelligence
PDF
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
PDF
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
PDF
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
PDF
Understanding Forklifts - TECH EHS Solution
PPTX
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
PPTX
Transform Your Business with a Software ERP System
PPTX
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
PDF
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
PDF
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
Internet Downloader Manager (IDM) Crack 6.42 Build 41
PDF
Upgrade and Innovation Strategies for SAP ERP Customers
PDF
PTS Company Brochure 2025 (1).pdf.......
Wondershare Filmora 15 Crack With Activation Key [2025
How to Migrate SBCGlobal Email to Yahoo Easily
wealthsignaloriginal-com-DS-text-... (1).pdf
Reimagine Home Health with the Power of Agentic AI​
Odoo Companies in India – Driving Business Transformation.pdf
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
Introduction to Artificial Intelligence
Adobe Premiere Pro 2025 (v24.5.0.057) Crack free
Flood Susceptibility Mapping Using Image-Based 2D-CNN Deep Learnin. Overview ...
SAP S4 Hana Brochure 3 (PTS SYSTEMS AND SOLUTIONS)
Understanding Forklifts - TECH EHS Solution
Oracle E-Business Suite: A Comprehensive Guide for Modern Enterprises
Transform Your Business with a Software ERP System
Lecture 3: Operating Systems Introduction to Computer Hardware Systems
Addressing The Cult of Project Management Tools-Why Disconnected Work is Hold...
Raksha Bandhan Grocery Pricing Trends in India 2025.pdf
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
Internet Downloader Manager (IDM) Crack 6.42 Build 41
Upgrade and Innovation Strategies for SAP ERP Customers
PTS Company Brochure 2025 (1).pdf.......

Handling inline assembly in Clang and LLVM

  • 1. Min-Yih “Min” Hsu @ LLVM Dev Meeting 2021 Handling inline assembly 
 in Clang and LLVM
  • 2. about:me “Min” Hsu • Computer Science PhD Candidate in University of California, Irvine • Code owner of M68k LLVM backend • Author of book “LLVM Techniques, Tips and Best Practices” (2021) 2
  • 3. How Inline Assembly is Processed in Clang & LLVM 3
  • 5. Introduction to inline assembly 5 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } * x86_64 assembly w/ AT&T syntax
  • 6. Introduction to inline assembly 5 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } * x86_64 assembly w/ AT&T syntax
  • 7. Introduction to inline assembly 5 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } foo: pushq %rbp movq %rsp, %rbp ... testb $1, -9(%rbp) je LBB0_2 ## InlineAsm Start movl %eax, %ebx addl %ebx, %esi ## InlineAsm End jmp LBB0_3 LBB0_2: movl -8(%rbp), %eax addl $87, %eax movl %eax, -8(%rbp) LBB0_3: popq %rbp retq * x86_64 assembly w/ AT&T syntax
  • 8. Introduction to inline assembly 5 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } foo: pushq %rbp movq %rsp, %rbp ... testb $1, -9(%rbp) je LBB0_2 ## InlineAsm Start movl %eax, %ebx addl %ebx, %esi ## InlineAsm End jmp LBB0_3 LBB0_2: movl -8(%rbp), %eax addl $87, %eax movl %eax, -8(%rbp) LBB0_3: popq %rbp retq * x86_64 assembly w/ AT&T syntax
  • 9. Introduction to inline assembly Why use inline assembly? 6 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } * x86_64 assembly w/ AT&T syntax
  • 10. Introduction to inline assembly Why use inline assembly? 6 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } Performance critical code * x86_64 assembly w/ AT&T syntax
  • 11. Introduction to inline assembly Why use inline assembly? 6 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } Performance critical code Low-level code e.g. Kernel, firmware * x86_64 assembly w/ AT&T syntax
  • 12. Introduction to inline assembly Why use inline assembly? 6 void foo(...) { int sum = 0; bool flag = ...; if (flag) asm ("movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); else sum += 87; } Performance critical code Low-level code e.g. Kernel, firmware Compiler optimizations “barrier” * x86_64 assembly w/ AT&T syntax
  • 13. Introduction to inline assembly 7 asm (“movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); * x86_64 assembly w/ AT&T syntax
  • 14. Introduction to inline assembly 7 asm (“movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); Assembly code (template) * x86_64 assembly w/ AT&T syntax
  • 15. Introduction to inline assembly 7 asm (“movl %%eax, %%ebxn" "addl %%ebx, %%esi" :::); Assembly code (template) * x86_64 assembly w/ AT&T syntax
  • 16. Introduction to inline assembly Output operands 8 int out_var; asm ("movl %%eax, %%ebxn" "addl %%ebx, %0" : "=r"(out_var) ::); * x86_64 assembly w/ AT&T syntax
  • 17. Introduction to inline assembly Output operands 8 int out_var; asm ("movl %%eax, %%ebxn" "addl %%ebx, %0" : "=r"(out_var) ::); * x86_64 assembly w/ AT&T syntax
  • 18. Introduction to inline assembly Output operands 8 int out_var; asm ("movl %%eax, %%ebxn" "addl %%ebx, %0" : "=r"(out_var) ::); Operand constraints * x86_64 assembly w/ AT&T syntax
  • 19. Introduction to inline assembly Operands constraints 9 int out_var; asm ("movl %%eax, %%ebxn" "addl %%ebx, %0" : "=r"(out_var) ::); * x86_64 assembly w/ AT&T syntax
  • 20. Introduction to inline assembly Operands constraints 9 int out_var; asm ("movl %%eax, %%ebxn" "addl %%ebx, %0" : "=r"(out_var) ::); * x86_64 assembly w/ AT&T syntax ## InlineAsm Start movl %eax, %ebx addl %ebx, %esi ## InlineAsm End
  • 21. Introduction to inline assembly Operands constraints 9 int out_var; asm ("movl %%eax, %%ebxn" "addl %%ebx, %0" : "=r"(out_var) ::); * x86_64 assembly w/ AT&T syntax ## InlineAsm Start movl %eax, %ebx addl %ebx, %esi ## InlineAsm End ## InlineAsm Start movl %eax, %ebx addl %ebx, -8(%ebp) ## InlineAsm End
  • 23. Operand constraints 10 • ‘r’ : General-purpose register operand • ‘i’ : Immediate integer operand • ‘m’ : Memory operand w/ arbitrary addressing mode Target-independent Constraints
  • 24. Operand constraints 10 • ‘r’ : General-purpose register operand • ‘i’ : Immediate integer operand • ‘m’ : Memory operand w/ arbitrary addressing mode Target-independent Constraints • ‘a’ : AL / AH / EAX / RAX • ‘I’ : Integer constant in the range of [0, 31] • ‘N’ : Unsigned 8-bit integer constant X86 Constraints
  • 25. Operand constraints 10 • ‘r’ : General-purpose register operand • ‘i’ : Immediate integer operand • ‘m’ : Memory operand w/ arbitrary addressing mode Target-independent Constraints • ‘a’ : AL / AH / EAX / RAX • ‘I’ : Integer constant in the range of [0, 31] • ‘N’ : Unsigned 8-bit integer constant X86 Constraints • ‘J’ : 16-bit signed integer constant • “Ci” : Constant integers • “Cj” : Constant signed integers that do NOT fi t in 16 bits M68k Constraints
  • 26. Operand constraints 10 • ‘r’ : General-purpose register operand • ‘i’ : Immediate integer operand • ‘m’ : Memory operand w/ arbitrary addressing mode Constraint Modifers Target-independent Constraints • ‘=‘ : This is an output operand • ‘+’ : This is an input / output operand • ‘a’ : AL / AH / EAX / RAX • ‘I’ : Integer constant in the range of [0, 31] • ‘N’ : Unsigned 8-bit integer constant X86 Constraints • ‘J’ : 16-bit signed integer constant • “Ci” : Constant integers • “Cj” : Constant signed integers that do NOT fi t in 16 bits M68k Constraints
  • 27. Introduction to inline assembly Input operands 11 int out_var, in_var; asm ("movl %1, %%ebxn" "addl %%ebx, %0" : “=r"(out_var) : “r”(in_var) :); * x86_64 assembly w/ AT&T syntax
  • 28. Introduction to inline assembly Input operands 11 int out_var, in_var; asm ("movl %1, %%ebxn" "addl %%ebx, %0" : “=r"(out_var) : “r”(in_var) :); * x86_64 assembly w/ AT&T syntax
  • 29. Introduction to inline assembly Input operands 11 int out_var, in_var; asm ("movl %1, %%ebxn" "addl %%ebx, %0" : “=r"(out_var) : “r”(in_var) :); Operand constraints * x86_64 assembly w/ AT&T syntax
  • 30. Introduction to inline assembly Clobber operands 12 int out_var, in_var; asm ("movl %1, %%ebxn" "addl %%ebx, %0" : “=r"(out_var) : “r”(in_var) : “ebx”); * x86_64 assembly w/ AT&T syntax
  • 31. Introduction to inline assembly Clobber operands 12 int out_var, in_var; asm ("movl %1, %%ebxn" "addl %%ebx, %0" : “=r"(out_var) : “r”(in_var) : “ebx”); * x86_64 assembly w/ AT&T syntax
  • 32. For more inline assembly syntax… 13 https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
  • 33. Handling inline assembly in Clang & LLVM Background 14
  • 34. Handling inline assembly in Clang & LLVM Background • Most parts of an inline assembly string are simply copied into the fi nal assembly fi le 14
  • 35. Handling inline assembly in Clang & LLVM Background • Most parts of an inline assembly string are simply copied into the fi nal assembly fi le • LLVM needs to “glue” inline assembly operands with the surrounding code 14
  • 36. Handling inline assembly in Clang & LLVM Background • Most parts of an inline assembly string are simply copied into the fi nal assembly fi le • LLVM needs to “glue” inline assembly operands with the surrounding code • Lots of target-speci fi c logics • In both Clang and the backend 14
  • 37. Handling inline assembly in Clang & LLVM Background • Most parts of an inline assembly string are simply copied into the fi nal assembly fi le • LLVM needs to “glue” inline assembly operands with the surrounding code • Lots of target-speci fi c logics • In both Clang and the backend • Target-speci fi c callbacks are scattered in the codebase • Documentation for this part is a little…shy 14
  • 39. Goals Learning inline assembly workflow in Clang / LLVM 15
  • 40. Goals Learning inline assembly workflow in Clang / LLVM A simple guide for backend developers to add inline assembly support 15
  • 41. Outline of target-specific logics in each stage 16 Clang Lowering LLVM IR Machine IR AsmPrinter
  • 42. Outline of target-specific logics in each stage 16 Clang Lowering LLVM IR Machine IR AsmPrinter • Simple validation on operand constraints • Converting constraints
  • 43. Outline of target-specific logics in each stage 16 Clang Lowering LLVM IR Machine IR AsmPrinter • Simple validation on operand constraints • Converting constraints • Classifying constraints • Constraint validations • Lowering the operands
  • 44. Outline of target-specific logics in each stage 16 Clang Lowering LLVM IR Machine IR AsmPrinter • Simple validation on operand constraints • Converting constraints • Classifying constraints • Constraint validations • Lowering the operands Print out di ff erent types of operands
  • 45. Outline of target-specific logics in each stage 17 Clang Lowering LLVM IR Machine IR AsmPrinter • Simple validation on operand constraints • Converting constraints • Classifying constraints • Constraint validations • Lowering the operands Print out di ff erent types of operands
  • 46. Operand constraint validations in Clang 18 bool TargetInfo::validateAsmConstraint(const char *&, ConstraintInfo &) const;
  • 47. Operand constraint validations in Clang 18 bool TargetInfo::validateAsmConstraint(const char *&, ConstraintInfo &) const; bool M68kTargetInfo::validateAsmConstraint(const char *&Name, ConstraintInfo &info) const { switch (*Name) { case 'a': // address register info.setAllowsRegister(); return true; } … }
  • 48. Operand constraint validations in Clang 19 bool TargetInfo::validateAsmConstraint(const char *&, ConstraintInfo &) const; bool M68kTargetInfo::validateAsmConstraint(const char *&Name, ConstraintInfo &info) const { switch (*Name) { case 'a': // address register info.setAllowsRegister(); return true; case 'J': // constant signed 16-bit integer info.setRequiresImmediate(std::numeric_limits<int16_t>::min(), std::numeric_limits<int16_t>::max()); return true; } … }
  • 49. Operand constraint validations in Clang Limitation on immediate value validations 20 void foo() { int32_t x; asm ("move.l %0, %%d1" : : "J" (x)); } * M68k assembly w/ Motorola syntax
  • 50. Operand constraint validations in Clang Limitation on immediate value validations 20 void foo() { int32_t x; asm ("move.l %0, %%d1" : : "J" (x)); } Constant signed 16-bit integer * M68k assembly w/ Motorola syntax
  • 51. Operand constraint validations in Clang Limitation on immediate value validations 20 void foo() { int32_t x; asm ("move.l %0, %%d1" : : "J" (x)); } $ clang -target m68k -fsyntax-only foo.c # No error $ clang -target m68k -emit-llvm foo.c # No error Constant signed 16-bit integer * M68k assembly w/ Motorola syntax
  • 52. Operand constraint validations in Clang Limitation on immediate value validations 20 void foo() { int32_t x; asm ("move.l %0, %%d1" : : "J" (x)); } $ clang -target m68k -fsyntax-only foo.c # No error $ clang -target m68k -emit-llvm foo.c # No error Constant signed 16-bit integer $ clang -target m68k -S foo.c error: constraint 'J' expects an integer constant expression * M68k assembly w/ Motorola syntax
  • 53. Inline assembly in LLVM IR 21 void foo() { const int x = 87; asm ("move.l %0, %%d1" : : "Ci" (x) : "d1"); } C/C++ * M68k assembly w/ Motorola syntax
  • 54. Inline assembly in LLVM IR 21 void foo() { const int x = 87; asm ("move.l %0, %%d1" : : "Ci" (x) : "d1"); } C/C++ call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) LLVM IR * M68k assembly w/ Motorola syntax
  • 55. Inline assembly in LLVM IR 21 void foo() { const int x = 87; asm ("move.l %0, %%d1" : : "Ci" (x) : "d1"); } C/C++ call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) LLVM IR * M68k assembly w/ Motorola syntax
  • 56. Inline assembly in LLVM IR 21 void foo() { const int x = 87; asm ("move.l %0, %%d1" : : "Ci" (x) : "d1"); } C/C++ call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) LLVM IR * M68k assembly w/ Motorola syntax
  • 57. Inline assembly in LLVM IR 21 void foo() { const int x = 87; asm ("move.l %0, %%d1" : : "Ci" (x) : "d1"); } C/C++ call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) LLVM IR * M68k assembly w/ Motorola syntax
  • 58. Inline assembly in LLVM IR 21 void foo() { const int x = 87; asm ("move.l %0, %%d1" : : "Ci" (x) : "d1"); } C/C++ call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) LLVM IR * M68k assembly w/ Motorola syntax
  • 59. Outline of target-specific logics in each stage 22 Clang Lowering LLVM IR Machine IR AsmPrinter • Simple validation on operand constraints • Converting constraints • Classifying constraints • Constraint validations • Lowering the operands Print out di ff erent types of operands
  • 60. 23 LLVM IR call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87)
  • 61. 23 LLVM IR SelectionDAG call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) t2: ch,glue = inlineasm ... "move.l $0, %d1", ..., TargetConstant:i32<87>, Register:i16 $d1
  • 62. 23 LLVM IR SelectionDAG Machine IR call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1 t2: ch,glue = inlineasm ... "move.l $0, %d1", ..., TargetConstant:i32<87>, Register:i16 $d1
  • 63. 23 LLVM IR SelectionDAG Machine IR call void asm sideeffect "move.l $0, %d1", “^Ci,~{d1}“(i32 87) INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1 t2: ch,glue = inlineasm ... "move.l $0, %d1", ..., TargetConstant:i32<87>, Register:i16 $d1
  • 68. Constraint classification 24 TargetLowering::ConstraintType M68kTargetLowering::getConstraintType(StringRef Constraint) const; • C_RegisterClass • C_Immediate • C_Memory Return: Ex: ’r’ Ex: ‘i’ Ex: ‘m’, ‘Q’ (AArch64)
  • 69. Constraint classification 24 TargetLowering::ConstraintType M68kTargetLowering::getConstraintType(StringRef Constraint) const; • C_RegisterClass • C_Immediate • C_Memory • C_Other Return: Ex: ’r’ Ex: ‘i’ Ex: ‘m’, ‘Q’ (AArch64)
  • 70. Lowering operands 25 getConstraintType Method in XXXTargetLowering Method in XXXISelDAGToDAG Will be invoked
  • 71. Lowering operands 25 getConstraintType getRegForInlineAsmConstraint C_RegisterClass Method in XXXTargetLowering Method in XXXISelDAGToDAG Will be invoked
  • 75. Lowering register operands 26 std::pair<unsigned, const TargetRegisterClass *> TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const;
  • 76. Lowering register operands 26 std::pair<unsigned, const TargetRegisterClass *> TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const; A speci fi c register or 0 if not applicable
  • 77. Lowering register operands 26 std::pair<unsigned, const TargetRegisterClass *> TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const; A speci fi c register or 0 if not applicable Valid register class to select from
  • 78. Lowering register operands M68k Example 27 std::pair<unsigned, const TargetRegisterClass *> M68kTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *, StringRef Constraint, MVT VT) const { switch (Constraint[0]) { case 'a': switch (VT.SimpleTy) { case MVT::i16: return std::make_pair(0U, &M68k::AR16RegClass); } } }
  • 79. Lowering register operands M68k Example 27 std::pair<unsigned, const TargetRegisterClass *> M68kTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *, StringRef Constraint, MVT VT) const { switch (Constraint[0]) { case 'a': switch (VT.SimpleTy) { case MVT::i16: return std::make_pair(0U, &M68k::AR16RegClass); } } }
  • 80. Lowering register operands X86 Example 28 std::pair<unsigned, const TargetRegisterClass *> X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *, StringRef Constraint, MVT VT) const { ... if (Constraint == "Yz") { // First SSE register (%xmm0). switch (VT.SimpleTy) { case MVT::f32: case MVT::i32: return std::make_pair(X86::XMM0, &X86::FR32RegClass); } } }
  • 81. Lowering register operands X86 Example 28 std::pair<unsigned, const TargetRegisterClass *> X86TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *, StringRef Constraint, MVT VT) const { ... if (Constraint == "Yz") { // First SSE register (%xmm0). switch (VT.SimpleTy) { case MVT::f32: case MVT::i32: return std::make_pair(X86::XMM0, &X86::FR32RegClass); } } }
  • 82. Lowering immediate / other operands 29 void TargetLowering:: LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops, SelectionDAG &DAG) const;
  • 83. Lowering immediate / other operands M68k Example 30 void M68kTargetLowering::LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops, SelectionDAG &DAG) const { switch (Constraint[0]) { case 'J': { // constant signed 16-bit integer } } }
  • 84. Lowering immediate / other operands M68k Example 31 void M68kTargetLowering::LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops, SelectionDAG &DAG) const { switch (Constraint[0]) { case 'J': { // constant signed 16-bit integer if (auto *C = dyn_cast<ConstantSDNode>(Op)) { int64_t Val = C->getSExtValue(); } } } }
  • 85. Lowering immediate / other operands M68k Example 32 void M68kTargetLowering::LowerAsmOperandForConstraint(SDValue Op, std::string &Constraint, std::vector<SDValue> &Ops, SelectionDAG &DAG) const { switch (Constraint[0]) { case 'J': { // constant signed 16-bit integer if (auto *C = dyn_cast<ConstantSDNode>(Op)) { int64_t Val = C->getSExtValue(); if (isInt<16>(Val)) { Ops.push_back(Op); return; } } } } }
  • 86. Lowering memory operands Memory constraint classi fi cation 33 unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const;
  • 87. Lowering memory operands Memory constraint classi fi cation 33 unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const; Return:
  • 88. Lowering memory operands Memory constraint classi fi cation 33 unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const; • InlineAsm::Constraint_m • InlineAsm::Constraint_o • InlineAsm::Constraint_v Return: Generic memory constraints
  • 89. Lowering memory operands Memory constraint classi fi cation 33 unsigned TargetLowering::getInlineAsmMemConstraint(StringRef ConstraintCode) const; • InlineAsm::Constraint_m • InlineAsm::Constraint_o • InlineAsm::Constraint_v Return: • InlineAsm::Constraint_A • InlineAsm::Constraint_Q Generic memory constraints Target-speci fi c constraints!
  • 90. Lowering memory operands Memory constraint classi fi cation — RISCV Example 34 unsigned RISCVTargetLowering:: getInlineAsmMemConstraint(StringRef ConstraintCode) const { switch (ConstraintCode[0]) { case 'A': return InlineAsm::Constraint_A; ... } ... }
  • 91. Lowering memory operands 35 bool SelectionDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps);
  • 92. Lowering memory operands RISCV Example 36 bool RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand( const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { switch (ConstraintID) { case InlineAsm::Constraint_A: OutOps.push_back(Op); return false; default: break; } return true; }
  • 93. Lowering memory operands Complex addressing mode — X86 Example 37 bool X86DAGToDAGISel:: SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { SDValue Op0, Op1, Op2, Op3, Op4; switch (ConstraintID) { case InlineAsm::Constraint_m: // memory if (!selectAddr(nullptr, Op, Op0, Op1, Op2, Op3, Op4)) return true; break; } OutOps.insert(OutOps.end(), {Op0, Op1, Op2, Op3, Op4}); return false; }
  • 94. Lowering memory operands Complex addressing mode — X86 Example 37 bool X86DAGToDAGISel:: SelectInlineAsmMemoryOperand(const SDValue &Op, unsigned ConstraintID, std::vector<SDValue> &OutOps) { SDValue Op0, Op1, Op2, Op3, Op4; switch (ConstraintID) { case InlineAsm::Constraint_m: // memory if (!selectAddr(nullptr, Op, Op0, Op1, Op2, Op3, Op4)) return true; break; } OutOps.insert(OutOps.end(), {Op0, Op1, Op2, Op3, Op4}); return false; }
  • 95. Outline of target-specific logics in each stage 38 Clang Lowering LLVM IR Machine IR AsmPrinter • Simple validation on operand constraints • Converting constraints • Classifying constraints • Constraint validations • Lowering the operands Print out di ff erent types of operands
  • 96. 39 Machine IR INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
  • 97. 39 Machine IR INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1
  • 98. 39 Machine IR INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1 move.l #87, %d1
  • 99. 39 Machine IR INLINEASM &"move.l $0, %d1", ..., /* imm */ 87, /* clobber */ $d1 move.l 87, %d1 move.l #87, %d1
  • 100. Printing asm operands 40 bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *, raw_ostream &O); bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *, raw_ostream &O);
  • 101. Printing non-memory asm operands M68k Example 41 void M68kAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, raw_ostream &OS) { const MachineOperand &MO = MI->getOperand(OpNum); switch (MO.getType()) { case MachineOperand::MO_Register: OS << "%" << M68kInstPrinter::getRegisterName(MO.getReg()); break; case MachineOperand::MO_Immediate: OS << '#' << MO.getImm(); break; ... } }
  • 102. Printing non-memory asm operands M68k Example 41 void M68kAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, raw_ostream &OS) { const MachineOperand &MO = MI->getOperand(OpNum); switch (MO.getType()) { case MachineOperand::MO_Register: OS << "%" << M68kInstPrinter::getRegisterName(MO.getReg()); break; case MachineOperand::MO_Immediate: OS << '#' << MO.getImm(); break; ... } }
  • 103. Printing non-memory asm operands M68k Example 41 void M68kAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, raw_ostream &OS) { const MachineOperand &MO = MI->getOperand(OpNum); switch (MO.getType()) { case MachineOperand::MO_Register: OS << "%" << M68kInstPrinter::getRegisterName(MO.getReg()); break; case MachineOperand::MO_Immediate: OS << '#' << MO.getImm(); break; ... } }
  • 105. Advanced topics Converting constraints in Clang Asm dialects Operand modifiers Multi-alternative constraints Constraint weights Turn (simple) inline asm into LLVM code 43
  • 106. Thank you! 44 GitHub: mshockwave Email: [email protected] 25% book discount code: 25MINLLVM Redeem: Nov 15 ~ Nov 20, 2021
  • 108. Converting constraints in Clang 46 An operand constraint is assumed to have only a single character by default
  • 109. Converting constraints in Clang 46 An operand constraint is assumed to have only a single character by default Example: “Ci”
  • 110. Converting constraints in Clang 46 An operand constraint is assumed to have only a single character by default Example: “Ci” -> “^Ci”
  • 111. Converting constraints in Clang 46 std::string M68kTargetInfo::convertConstraint(const char *&Constraint) const override { if (*Constraint == 'C') // Two-character constraint; add "^" hint for later parsing return std::string("^") + std::string(Constraint++, 2); return std::string(1, *Constraint); } An operand constraint is assumed to have only a single character by default Example: “Ci” -> “^Ci”
  • 112. Operand constraint validations in Clang Limitation on immediate value validations (cont’d) 47 bool M68kTargetInfo::validateAsmConstraint(const char *&Name, ConstraintInfo &info) const { switch (*Name) { … case 'C': ++Name; switch (*Name) { case 'i': // constant integer case 'j': // integer constant that doesn't fit in 16 bits info.setRequiresImmediate(); return true; } break; } … }