[llvm] a1c447d - [C API]: Add getters for inline assembly template string, constraints, and flags

Justin Bogner via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 15 21:52:22 PDT 2023


Author: Justin Bogner
Date: 2023-08-15T21:49:28-07:00
New Revision: a1c447d9ddcdc00a6da9c8147626c1013d60315d

URL: https://github.com/llvm/llvm-project/commit/a1c447d9ddcdc00a6da9c8147626c1013d60315d
DIFF: https://github.com/llvm/llvm-project/commit/a1c447d9ddcdc00a6da9c8147626c1013d60315d.diff

LOG: [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

Added: 
    

Modified: 
    llvm/include/llvm-c/Core.h
    llvm/lib/IR/Core.cpp
    llvm/test/Bindings/llvm-c/echo.ll
    llvm/tools/llvm-c-test/echo.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 8f5fb152a7d72d..35c58caee786e9 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -904,12 +904,58 @@ void LLVMAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm, size_t Len);
  *
  * @see InlineAsm::get()
  */
-LLVMValueRef LLVMGetInlineAsm(LLVMTypeRef Ty, char *AsmString,
-                              size_t AsmStringSize, char *Constraints,
+LLVMValueRef LLVMGetInlineAsm(LLVMTypeRef Ty, const char *AsmString,
+                              size_t AsmStringSize, const char *Constraints,
                               size_t ConstraintsSize, LLVMBool HasSideEffects,
                               LLVMBool IsAlignStack,
                               LLVMInlineAsmDialect Dialect, LLVMBool CanThrow);
 
+/**
+ * Get the template string used for an inline assembly snippet
+ *
+ */
+const char *LLVMGetInlineAsmAsmString(LLVMValueRef InlineAsmVal, size_t *Len);
+
+/**
+ * Get the raw constraint string for an inline assembly snippet
+ *
+ */
+const char *LLVMGetInlineAsmConstraintString(LLVMValueRef InlineAsmVal,
+                                             size_t *Len);
+
+/**
+ * Get the dialect used by the inline asm snippet
+ *
+ */
+LLVMInlineAsmDialect LLVMGetInlineAsmDialect(LLVMValueRef InlineAsmVal);
+
+/**
+ * Get the function type of the inline assembly snippet. The same type that
+ * was passed into LLVMGetInlineAsm originally
+ *
+ * @see LLVMGetInlineAsm
+ *
+ */
+LLVMTypeRef LLVMGetInlineAsmFunctionType(LLVMValueRef InlineAsmVal);
+
+/**
+ * Get if the inline asm snippet has side effects
+ *
+ */
+LLVMBool LLVMGetInlineAsmHasSideEffects(LLVMValueRef InlineAsmVal);
+
+/**
+ * Get if the inline asm snippet needs an aligned stack
+ *
+ */
+LLVMBool LLVMGetInlineAsmNeedsAlignedStack(LLVMValueRef InlineAsmVal);
+
+/**
+ * Get if the inline asm snippet may unwind the stack
+ *
+ */
+LLVMBool LLVMGetInlineAsmCanUnwind(LLVMValueRef InlineAsmVal);
+
 /**
  * Obtain the context to which this module is associated.
  *

diff  --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 129e91b5ba3d19..207d57ecc8b24b 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -460,8 +460,8 @@ const char *LLVMGetModuleInlineAsm(LLVMModuleRef M, size_t *Len) {
   return Str.c_str();
 }
 
-LLVMValueRef LLVMGetInlineAsm(LLVMTypeRef Ty, char *AsmString,
-                              size_t AsmStringSize, char *Constraints,
+LLVMValueRef LLVMGetInlineAsm(LLVMTypeRef Ty, const char *AsmString,
+                              size_t AsmStringSize, const char *Constraints,
                               size_t ConstraintsSize, LLVMBool HasSideEffects,
                               LLVMBool IsAlignStack,
                               LLVMInlineAsmDialect Dialect, LLVMBool CanThrow) {
@@ -480,6 +480,61 @@ LLVMValueRef LLVMGetInlineAsm(LLVMTypeRef Ty, char *AsmString,
                              HasSideEffects, IsAlignStack, AD, CanThrow));
 }
 
+const char *LLVMGetInlineAsmAsmString(LLVMValueRef InlineAsmVal, size_t *Len) {
+
+  Value *Val = unwrap<Value>(InlineAsmVal);
+  const std::string &AsmString = cast<InlineAsm>(Val)->getAsmString();
+
+  *Len = AsmString.length();
+  return AsmString.c_str();
+}
+
+const char *LLVMGetInlineAsmConstraintString(LLVMValueRef InlineAsmVal,
+                                             size_t *Len) {
+  Value *Val = unwrap<Value>(InlineAsmVal);
+  const std::string &ConstraintString =
+      cast<InlineAsm>(Val)->getConstraintString();
+
+  *Len = ConstraintString.length();
+  return ConstraintString.c_str();
+}
+
+LLVMInlineAsmDialect LLVMGetInlineAsmDialect(LLVMValueRef InlineAsmVal) {
+
+  Value *Val = unwrap<Value>(InlineAsmVal);
+  InlineAsm::AsmDialect Dialect = cast<InlineAsm>(Val)->getDialect();
+
+  switch (Dialect) {
+  case InlineAsm::AD_ATT:
+    return LLVMInlineAsmDialectATT;
+  case InlineAsm::AD_Intel:
+    return LLVMInlineAsmDialectIntel;
+  }
+
+  llvm_unreachable("Unrecognized inline assembly dialect");
+  return LLVMInlineAsmDialectATT;
+}
+
+LLVMTypeRef LLVMGetInlineAsmFunctionType(LLVMValueRef InlineAsmVal) {
+  Value *Val = unwrap<Value>(InlineAsmVal);
+  return (LLVMTypeRef)cast<InlineAsm>(Val)->getFunctionType();
+}
+
+LLVMBool LLVMGetInlineAsmHasSideEffects(LLVMValueRef InlineAsmVal) {
+  Value *Val = unwrap<Value>(InlineAsmVal);
+  return cast<InlineAsm>(Val)->hasSideEffects();
+}
+
+LLVMBool LLVMGetInlineAsmNeedsAlignedStack(LLVMValueRef InlineAsmVal) {
+  Value *Val = unwrap<Value>(InlineAsmVal);
+  return cast<InlineAsm>(Val)->isAlignStack();
+}
+
+LLVMBool LLVMGetInlineAsmCanUnwind(LLVMValueRef InlineAsmVal) {
+  Value *Val = unwrap<Value>(InlineAsmVal);
+  return cast<InlineAsm>(Val)->canThrow();
+}
+
 /*--.. Operations on module contexts ......................................--*/
 LLVMContextRef LLVMGetModuleContext(LLVMModuleRef M) {
   return wrap(&unwrap(M)->getContext());

diff  --git a/llvm/test/Bindings/llvm-c/echo.ll b/llvm/test/Bindings/llvm-c/echo.ll
index 3f20fb87578547..5daa238bfb8e53 100644
--- a/llvm/test/Bindings/llvm-c/echo.ll
+++ b/llvm/test/Bindings/llvm-c/echo.ll
@@ -113,6 +113,22 @@ define i32 @notailcall() {
   ret i32 %1
 }
 
+define i32 @call_inline_asm(i32 %0) {
+	; Test Intel syntax
+	%2 = tail call i32 asm sideeffect inteldialect "mov $0, $1", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %0)
+	%3 = tail call i32 asm sideeffect inteldialect "lea $0, [$1+$2]", "=r,r,r,~{dirflag},~{fpsr},~{flags}"(i32 %0, i32 %2)
+	%4 = tail call i32 asm inteldialect "mov $0, $1", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %3)
+	%5 = tail call i32 asm inteldialect unwind "mov $0, $1", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %4)
+	%6 = tail call i32 asm alignstack inteldialect "mov $0, $1", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %5)
+
+	; Test AT&T syntax
+	%7 = tail call i32 asm "mov $1, $0", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %6)
+	%8 = tail call i32 asm sideeffect "mov $1, $0", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %7)
+	%9 = tail call i32 asm alignstack "mov $1, $0", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %8)
+	%10 = tail call i32 asm alignstack unwind "mov $1, $0", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %9)
+	ret i32 %10
+}
+
 define i32 @cond(i32 %a, i32 %b) {
   br label %br
 unreachable:

diff  --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index 91c554510d32aa..faf9838a0069af 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -406,6 +406,32 @@ static LLVMValueRef clone_constant_impl(LLVMValueRef Cst, LLVMModuleRef M) {
   }
 }
 
+static LLVMValueRef clone_inline_asm(LLVMValueRef Asm, LLVMModuleRef M) {
+
+  if (!LLVMIsAInlineAsm(Asm))
+      report_fatal_error("Expected inline assembly");
+
+  size_t AsmStringSize = 0;
+  const char *AsmString = LLVMGetInlineAsmAsmString(Asm, &AsmStringSize);
+
+  size_t ConstraintStringSize = 0;
+  const char *ConstraintString =
+      LLVMGetInlineAsmConstraintString(Asm, &ConstraintStringSize);
+
+  LLVMInlineAsmDialect AsmDialect = LLVMGetInlineAsmDialect(Asm);
+
+  LLVMTypeRef AsmFunctionType = LLVMGetInlineAsmFunctionType(Asm);
+
+  LLVMBool HasSideEffects = LLVMGetInlineAsmHasSideEffects(Asm);
+  LLVMBool NeedsAlignStack = LLVMGetInlineAsmNeedsAlignedStack(Asm);
+  LLVMBool CanUnwind = LLVMGetInlineAsmCanUnwind(Asm);
+
+  return LLVMGetInlineAsm(AsmFunctionType, AsmString, AsmStringSize,
+                          ConstraintString, ConstraintStringSize,
+                          HasSideEffects, NeedsAlignStack, AsmDialect,
+                          CanUnwind);
+}
+
 struct FunCloner {
   LLVMValueRef Fun;
   LLVMModuleRef M;
@@ -435,6 +461,10 @@ struct FunCloner {
     if (i != VMap.end())
       return i->second;
 
+    // Inline assembly is a Value, but not an Instruction
+    if (LLVMIsAInlineAsm(Src))
+      return clone_inline_asm(Src, M);
+
     if (!LLVMIsAInstruction(Src))
       report_fatal_error("Expected an instruction");
 


        


More information about the llvm-commits mailing list