Skip to content

Commit a1c447d

Browse files
committed
[C API]: Add getters for inline assembly template string, constraints, and flags
This change adds support for accessing information about inline assembly calls through the C API, enough to be able to round-trip the information. This partially addresses https://llvm.org/pr42692 which points out gaps in the C API Getters for each of the parameters to LLVMGetInlineAsm/InlineAsm::get have been added, such that the C API now has enough surface to clone inline assembly calls This API currently only returns the raw constraint string via LLVMGetInlineAsmConstraintString: it may be prudent to also expose the parsed constraints via InlineAsm::ParseConstraints, but I wasn't sure how that should look like. This at least exposes the information for clients Patch by Benji Smith. Thanks! Differential Revision: https://reviews.llvm.org/D153185
1 parent e17667b commit a1c447d

File tree

4 files changed

+151
-4
lines changed

4 files changed

+151
-4
lines changed

llvm/include/llvm-c/Core.h

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -904,12 +904,58 @@ void LLVMAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm, size_t Len);
904904
*
905905
* @see InlineAsm::get()
906906
*/
907-
LLVMValueRef LLVMGetInlineAsm(LLVMTypeRef Ty, char *AsmString,
908-
size_t AsmStringSize, char *Constraints,
907+
LLVMValueRef LLVMGetInlineAsm(LLVMTypeRef Ty, const char *AsmString,
908+
size_t AsmStringSize, const char *Constraints,
909909
size_t ConstraintsSize, LLVMBool HasSideEffects,
910910
LLVMBool IsAlignStack,
911911
LLVMInlineAsmDialect Dialect, LLVMBool CanThrow);
912912

913+
/**
914+
* Get the template string used for an inline assembly snippet
915+
*
916+
*/
917+
const char *LLVMGetInlineAsmAsmString(LLVMValueRef InlineAsmVal, size_t *Len);
918+
919+
/**
920+
* Get the raw constraint string for an inline assembly snippet
921+
*
922+
*/
923+
const char *LLVMGetInlineAsmConstraintString(LLVMValueRef InlineAsmVal,
924+
size_t *Len);
925+
926+
/**
927+
* Get the dialect used by the inline asm snippet
928+
*
929+
*/
930+
LLVMInlineAsmDialect LLVMGetInlineAsmDialect(LLVMValueRef InlineAsmVal);
931+
932+
/**
933+
* Get the function type of the inline assembly snippet. The same type that
934+
* was passed into LLVMGetInlineAsm originally
935+
*
936+
* @see LLVMGetInlineAsm
937+
*
938+
*/
939+
LLVMTypeRef LLVMGetInlineAsmFunctionType(LLVMValueRef InlineAsmVal);
940+
941+
/**
942+
* Get if the inline asm snippet has side effects
943+
*
944+
*/
945+
LLVMBool LLVMGetInlineAsmHasSideEffects(LLVMValueRef InlineAsmVal);
946+
947+
/**
948+
* Get if the inline asm snippet needs an aligned stack
949+
*
950+
*/
951+
LLVMBool LLVMGetInlineAsmNeedsAlignedStack(LLVMValueRef InlineAsmVal);
952+
953+
/**
954+
* Get if the inline asm snippet may unwind the stack
955+
*
956+
*/
957+
LLVMBool LLVMGetInlineAsmCanUnwind(LLVMValueRef InlineAsmVal);
958+
913959
/**
914960
* Obtain the context to which this module is associated.
915961
*

llvm/lib/IR/Core.cpp

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,8 @@ const char *LLVMGetModuleInlineAsm(LLVMModuleRef M, size_t *Len) {
460460
return Str.c_str();
461461
}
462462

463-
LLVMValueRef LLVMGetInlineAsm(LLVMTypeRef Ty, char *AsmString,
464-
size_t AsmStringSize, char *Constraints,
463+
LLVMValueRef LLVMGetInlineAsm(LLVMTypeRef Ty, const char *AsmString,
464+
size_t AsmStringSize, const char *Constraints,
465465
size_t ConstraintsSize, LLVMBool HasSideEffects,
466466
LLVMBool IsAlignStack,
467467
LLVMInlineAsmDialect Dialect, LLVMBool CanThrow) {
@@ -480,6 +480,61 @@ LLVMValueRef LLVMGetInlineAsm(LLVMTypeRef Ty, char *AsmString,
480480
HasSideEffects, IsAlignStack, AD, CanThrow));
481481
}
482482

483+
const char *LLVMGetInlineAsmAsmString(LLVMValueRef InlineAsmVal, size_t *Len) {
484+
485+
Value *Val = unwrap<Value>(InlineAsmVal);
486+
const std::string &AsmString = cast<InlineAsm>(Val)->getAsmString();
487+
488+
*Len = AsmString.length();
489+
return AsmString.c_str();
490+
}
491+
492+
const char *LLVMGetInlineAsmConstraintString(LLVMValueRef InlineAsmVal,
493+
size_t *Len) {
494+
Value *Val = unwrap<Value>(InlineAsmVal);
495+
const std::string &ConstraintString =
496+
cast<InlineAsm>(Val)->getConstraintString();
497+
498+
*Len = ConstraintString.length();
499+
return ConstraintString.c_str();
500+
}
501+
502+
LLVMInlineAsmDialect LLVMGetInlineAsmDialect(LLVMValueRef InlineAsmVal) {
503+
504+
Value *Val = unwrap<Value>(InlineAsmVal);
505+
InlineAsm::AsmDialect Dialect = cast<InlineAsm>(Val)->getDialect();
506+
507+
switch (Dialect) {
508+
case InlineAsm::AD_ATT:
509+
return LLVMInlineAsmDialectATT;
510+
case InlineAsm::AD_Intel:
511+
return LLVMInlineAsmDialectIntel;
512+
}
513+
514+
llvm_unreachable("Unrecognized inline assembly dialect");
515+
return LLVMInlineAsmDialectATT;
516+
}
517+
518+
LLVMTypeRef LLVMGetInlineAsmFunctionType(LLVMValueRef InlineAsmVal) {
519+
Value *Val = unwrap<Value>(InlineAsmVal);
520+
return (LLVMTypeRef)cast<InlineAsm>(Val)->getFunctionType();
521+
}
522+
523+
LLVMBool LLVMGetInlineAsmHasSideEffects(LLVMValueRef InlineAsmVal) {
524+
Value *Val = unwrap<Value>(InlineAsmVal);
525+
return cast<InlineAsm>(Val)->hasSideEffects();
526+
}
527+
528+
LLVMBool LLVMGetInlineAsmNeedsAlignedStack(LLVMValueRef InlineAsmVal) {
529+
Value *Val = unwrap<Value>(InlineAsmVal);
530+
return cast<InlineAsm>(Val)->isAlignStack();
531+
}
532+
533+
LLVMBool LLVMGetInlineAsmCanUnwind(LLVMValueRef InlineAsmVal) {
534+
Value *Val = unwrap<Value>(InlineAsmVal);
535+
return cast<InlineAsm>(Val)->canThrow();
536+
}
537+
483538
/*--.. Operations on module contexts ......................................--*/
484539
LLVMContextRef LLVMGetModuleContext(LLVMModuleRef M) {
485540
return wrap(&unwrap(M)->getContext());

llvm/test/Bindings/llvm-c/echo.ll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,22 @@ define i32 @notailcall() {
113113
ret i32 %1
114114
}
115115

116+
define i32 @call_inline_asm(i32 %0) {
117+
; Test Intel syntax
118+
%2 = tail call i32 asm sideeffect inteldialect "mov $0, $1", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %0)
119+
%3 = tail call i32 asm sideeffect inteldialect "lea $0, [$1+$2]", "=r,r,r,~{dirflag},~{fpsr},~{flags}"(i32 %0, i32 %2)
120+
%4 = tail call i32 asm inteldialect "mov $0, $1", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %3)
121+
%5 = tail call i32 asm inteldialect unwind "mov $0, $1", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %4)
122+
%6 = tail call i32 asm alignstack inteldialect "mov $0, $1", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %5)
123+
124+
; Test AT&T syntax
125+
%7 = tail call i32 asm "mov $1, $0", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %6)
126+
%8 = tail call i32 asm sideeffect "mov $1, $0", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %7)
127+
%9 = tail call i32 asm alignstack "mov $1, $0", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %8)
128+
%10 = tail call i32 asm alignstack unwind "mov $1, $0", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %9)
129+
ret i32 %10
130+
}
131+
116132
define i32 @cond(i32 %a, i32 %b) {
117133
br label %br
118134
unreachable:

llvm/tools/llvm-c-test/echo.cpp

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,32 @@ static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M) {
406406
}
407407
}
408408

409+
static LLVMValueRef clone_inline_asm(LLVMValueRef Asm, LLVMModuleRef M) {
410+
411+
if (!LLVMIsAInlineAsm(Asm))
412+
report_fatal_error("Expected inline assembly");
413+
414+
size_t AsmStringSize = 0;
415+
const char *AsmString = LLVMGetInlineAsmAsmString(Asm, &AsmStringSize);
416+
417+
size_t ConstraintStringSize = 0;
418+
const char *ConstraintString =
419+
LLVMGetInlineAsmConstraintString(Asm, &ConstraintStringSize);
420+
421+
LLVMInlineAsmDialect AsmDialect = LLVMGetInlineAsmDialect(Asm);
422+
423+
LLVMTypeRef AsmFunctionType = LLVMGetInlineAsmFunctionType(Asm);
424+
425+
LLVMBool HasSideEffects = LLVMGetInlineAsmHasSideEffects(Asm);
426+
LLVMBool NeedsAlignStack = LLVMGetInlineAsmNeedsAlignedStack(Asm);
427+
LLVMBool CanUnwind = LLVMGetInlineAsmCanUnwind(Asm);
428+
429+
return LLVMGetInlineAsm(AsmFunctionType, AsmString, AsmStringSize,
430+
ConstraintString, ConstraintStringSize,
431+
HasSideEffects, NeedsAlignStack, AsmDialect,
432+
CanUnwind);
433+
}
434+
409435
struct FunCloner {
410436
LLVMValueRef Fun;
411437
LLVMModuleRef M;
@@ -435,6 +461,10 @@ struct FunCloner {
435461
if (i != VMap.end())
436462
return i->second;
437463

464+
// Inline assembly is a Value, but not an Instruction
465+
if (LLVMIsAInlineAsm(Src))
466+
return clone_inline_asm(Src, M);
467+
438468
if (!LLVMIsAInstruction(Src))
439469
report_fatal_error("Expected an instruction");
440470

0 commit comments

Comments
 (0)