[clang] [X86]Add support for _outp{|w|d} (PR #93774)

Malay Sanghi via cfe-commits cfe-commits at lists.llvm.org
Thu May 30 00:54:41 PDT 2024


https://github.com/MalaySanghi updated https://github.com/llvm/llvm-project/pull/93774

>From 38359132ea0b3b56900ba48827c86a93c017223a Mon Sep 17 00:00:00 2001
From: Malay Sanghi <malay.sanghi at intel.com>
Date: Wed, 29 May 2024 22:40:47 -0700
Subject: [PATCH 1/2] Add support for _outp{|w|d}

---
 clang/lib/Headers/intrin.h                 | 20 +++++
 clang/test/CodeGen/X86/ms-x86-intrinsics.c | 85 ++++++++++++++++++++++
 2 files changed, 105 insertions(+)

diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h
index 5ceb986a1f652..21a3f030216e6 100644
--- a/clang/lib/Headers/intrin.h
+++ b/clang/lib/Headers/intrin.h
@@ -329,6 +329,26 @@ static __inline__ void __DEFAULT_FN_ATTRS __stosq(unsigned __int64 *__dst,
 static __inline__ void __DEFAULT_FN_ATTRS __halt(void) {
   __asm__ volatile("hlt");
 }
+
+static __inline__ int __DEFAULT_FN_ATTRS _outp(unsigned short port, int data) {
+  __asm__ volatile("outb %b0, %w1" : : "a"(data), "Nd"(port) : "memory");
+  return data;
+}
+
+static __inline__ unsigned short __DEFAULT_FN_ATTRS
+_outpw(unsigned short port, unsigned short data) {
+  __asm__ volatile("outw %w0, %w1" : : "a"(data), "Nd"(port) : "memory");
+  return data;
+}
+
+static __inline__ unsigned long __DEFAULT_FN_ATTRS _outpd(unsigned short port,
+                                                          unsigned long data) {
+  __asm__ volatile("outl %k0, %w1" : : "a"(data), "Nd"(port) : "memory");
+  return data;
+}
+
+#define outp(port, data) _outp(port, data)
+#define outpw(R, D) _outpw(port, data)
 #endif
 
 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
diff --git a/clang/test/CodeGen/X86/ms-x86-intrinsics.c b/clang/test/CodeGen/X86/ms-x86-intrinsics.c
index aa557c8e19a83..e990ccd3449ac 100644
--- a/clang/test/CodeGen/X86/ms-x86-intrinsics.c
+++ b/clang/test/CodeGen/X86/ms-x86-intrinsics.c
@@ -63,6 +63,91 @@ unsigned __int64 test__emulu(unsigned int a, unsigned int b) {
 // CHECK: [[RES:%[0-9]+]] = mul nuw i64 [[Y]], [[X]]
 // CHECK: ret i64 [[RES]]
 
+//
+// CHECK-I386-LABEL: define dso_local noundef i32 @test_outp(
+// CHECK-I386-SAME: i16 noundef zeroext [[PORT:%.*]], i32 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
+// CHECK-I386-NEXT:  [[ENTRY:.*:]]
+// CHECK-I386-NEXT:    tail call void asm sideeffect "outb ${0:b}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR3:[0-9]+]], !srcloc [[META4:![0-9]+]]
+// CHECK-I386-NEXT:    ret i32 [[DATA]]
+//
+// CHECK-X64-LABEL: define dso_local noundef i32 @test_outp(
+// CHECK-X64-SAME: i16 noundef [[PORT:%.*]], i32 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
+// CHECK-X64-NEXT:  [[ENTRY:.*:]]
+// CHECK-X64-NEXT:    tail call void asm sideeffect "outb ${0:b}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR5:[0-9]+]], !srcloc [[META3:![0-9]+]]
+// CHECK-X64-NEXT:    ret i32 [[DATA]]
+//
+int test_outp(unsigned short port, int data) {
+    return _outp(port, data);
+}
+
+//
+// CHECK-I386-LABEL: define dso_local noundef zeroext i16 @test_outpw(
+// CHECK-I386-SAME: i16 noundef zeroext [[PORT:%.*]], i16 noundef returned zeroext [[DATA:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// CHECK-I386-NEXT:  [[ENTRY:.*:]]
+// CHECK-I386-NEXT:    tail call void asm sideeffect "outw ${0:w}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i16 [[DATA]], i16 [[PORT]]) #[[ATTR3]], !srcloc [[META5:![0-9]+]]
+// CHECK-I386-NEXT:    ret i16 [[DATA]]
+//
+// CHECK-X64-LABEL: define dso_local noundef i16 @test_outpw(
+// CHECK-X64-SAME: i16 noundef [[PORT:%.*]], i16 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR1]] {
+// CHECK-X64-NEXT:  [[ENTRY:.*:]]
+// CHECK-X64-NEXT:    tail call void asm sideeffect "outw ${0:w}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i16 [[DATA]], i16 [[PORT]]) #[[ATTR5]], !srcloc [[META4:![0-9]+]]
+// CHECK-X64-NEXT:    ret i16 [[DATA]]
+//
+unsigned short test_outpw(unsigned short port, unsigned short data) {
+    return _outpw(port, data);
+}
+
+//
+// CHECK-I386-LABEL: define dso_local noundef i32 @test_outpd(
+// CHECK-I386-SAME: i16 noundef zeroext [[PORT:%.*]], i32 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// CHECK-I386-NEXT:  [[ENTRY:.*:]]
+// CHECK-I386-NEXT:    tail call void asm sideeffect "outl ${0:k}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR3]], !srcloc [[META6:![0-9]+]]
+// CHECK-I386-NEXT:    ret i32 [[DATA]]
+//
+// CHECK-X64-LABEL: define dso_local noundef i32 @test_outpd(
+// CHECK-X64-SAME: i16 noundef [[PORT:%.*]], i32 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR1]] {
+// CHECK-X64-NEXT:  [[ENTRY:.*:]]
+// CHECK-X64-NEXT:    tail call void asm sideeffect "outl ${0:k}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR5]], !srcloc [[META5:![0-9]+]]
+// CHECK-X64-NEXT:    ret i32 [[DATA]]
+//
+unsigned long test_outpd(unsigned short port, unsigned long data) {
+    return _outpd(port, data);
+}
+
+//
+// CHECK-I386-LABEL: define dso_local noundef i32 @test_outp2(
+// CHECK-I386-SAME: i16 noundef zeroext [[PORT:%.*]], i32 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// CHECK-I386-NEXT:  [[ENTRY:.*:]]
+// CHECK-I386-NEXT:    tail call void asm sideeffect "outb ${0:b}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR3]], !srcloc [[META4]]
+// CHECK-I386-NEXT:    ret i32 [[DATA]]
+//
+// CHECK-X64-LABEL: define dso_local noundef i32 @test_outp2(
+// CHECK-X64-SAME: i16 noundef [[PORT:%.*]], i32 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR1]] {
+// CHECK-X64-NEXT:  [[ENTRY:.*:]]
+// CHECK-X64-NEXT:    tail call void asm sideeffect "outb ${0:b}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR5]], !srcloc [[META3]]
+// CHECK-X64-NEXT:    ret i32 [[DATA]]
+//
+int test_outp2(unsigned short port, int data) {
+    return outp(port, data);
+}
+
+//
+// CHECK-I386-LABEL: define dso_local noundef zeroext i16 @test_outpw2(
+// CHECK-I386-SAME: i16 noundef zeroext [[PORT:%.*]], i16 noundef returned zeroext [[DATA:%.*]]) local_unnamed_addr #[[ATTR2]] {
+// CHECK-I386-NEXT:  [[ENTRY:.*:]]
+// CHECK-I386-NEXT:    tail call void asm sideeffect "outw ${0:w}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i16 [[DATA]], i16 [[PORT]]) #[[ATTR3]], !srcloc [[META5]]
+// CHECK-I386-NEXT:    ret i16 [[DATA]]
+//
+// CHECK-X64-LABEL: define dso_local noundef i16 @test_outpw2(
+// CHECK-X64-SAME: i16 noundef [[PORT:%.*]], i16 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR1]] {
+// CHECK-X64-NEXT:  [[ENTRY:.*:]]
+// CHECK-X64-NEXT:    tail call void asm sideeffect "outw ${0:w}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i16 [[DATA]], i16 [[PORT]]) #[[ATTR5]], !srcloc [[META4]]
+// CHECK-X64-NEXT:    ret i16 [[DATA]]
+//
+unsigned short test_outpw2(unsigned short port, unsigned short data) {
+    return outpw(port, data);
+}
+
 #if defined(__x86_64__)
 
 char test__readgsbyte(unsigned long Offset) {

>From a5704660eebde130d17b0a72b0a757d9627aaf21 Mon Sep 17 00:00:00 2001
From: Malay Sanghi <malay.sanghi at intel.com>
Date: Thu, 30 May 2024 00:01:45 -0700
Subject: [PATCH 2/2] remove memory constraint and fix definition.

---
 clang/lib/Headers/intrin.h                 | 10 +++++-----
 clang/test/CodeGen/X86/ms-x86-intrinsics.c | 20 ++++++++++----------
 2 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h
index 21a3f030216e6..1d56952f06cef 100644
--- a/clang/lib/Headers/intrin.h
+++ b/clang/lib/Headers/intrin.h
@@ -331,24 +331,24 @@ static __inline__ void __DEFAULT_FN_ATTRS __halt(void) {
 }
 
 static __inline__ int __DEFAULT_FN_ATTRS _outp(unsigned short port, int data) {
-  __asm__ volatile("outb %b0, %w1" : : "a"(data), "Nd"(port) : "memory");
+  __asm__ volatile("outb %b0, %w1" : : "a"(data), "Nd"(port));
   return data;
 }
 
 static __inline__ unsigned short __DEFAULT_FN_ATTRS
 _outpw(unsigned short port, unsigned short data) {
-  __asm__ volatile("outw %w0, %w1" : : "a"(data), "Nd"(port) : "memory");
+  __asm__ volatile("outw %w0, %w1" : : "a"(data), "Nd"(port));
   return data;
 }
 
 static __inline__ unsigned long __DEFAULT_FN_ATTRS _outpd(unsigned short port,
                                                           unsigned long data) {
-  __asm__ volatile("outl %k0, %w1" : : "a"(data), "Nd"(port) : "memory");
+  __asm__ volatile("outl %k0, %w1" : : "a"(data), "Nd"(port));
   return data;
 }
 
-#define outp(port, data) _outp(port, data)
-#define outpw(R, D) _outpw(port, data)
+#define outp(port, data) _outp((port), (data))
+#define outpw(port, data) _outpw((port), (data))
 #endif
 
 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__)
diff --git a/clang/test/CodeGen/X86/ms-x86-intrinsics.c b/clang/test/CodeGen/X86/ms-x86-intrinsics.c
index e990ccd3449ac..423fbc8477d0a 100644
--- a/clang/test/CodeGen/X86/ms-x86-intrinsics.c
+++ b/clang/test/CodeGen/X86/ms-x86-intrinsics.c
@@ -67,13 +67,13 @@ unsigned __int64 test__emulu(unsigned int a, unsigned int b) {
 // CHECK-I386-LABEL: define dso_local noundef i32 @test_outp(
 // CHECK-I386-SAME: i16 noundef zeroext [[PORT:%.*]], i32 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR2:[0-9]+]] {
 // CHECK-I386-NEXT:  [[ENTRY:.*:]]
-// CHECK-I386-NEXT:    tail call void asm sideeffect "outb ${0:b}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR3:[0-9]+]], !srcloc [[META4:![0-9]+]]
+// CHECK-I386-NEXT:    tail call void asm sideeffect "outb ${0:b}, ${1:w}", "{ax},N{dx},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR3:[0-9]+]], !srcloc [[META4:![0-9]+]]
 // CHECK-I386-NEXT:    ret i32 [[DATA]]
 //
 // CHECK-X64-LABEL: define dso_local noundef i32 @test_outp(
 // CHECK-X64-SAME: i16 noundef [[PORT:%.*]], i32 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
 // CHECK-X64-NEXT:  [[ENTRY:.*:]]
-// CHECK-X64-NEXT:    tail call void asm sideeffect "outb ${0:b}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR5:[0-9]+]], !srcloc [[META3:![0-9]+]]
+// CHECK-X64-NEXT:    tail call void asm sideeffect "outb ${0:b}, ${1:w}", "{ax},N{dx},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR5:[0-9]+]], !srcloc [[META3:![0-9]+]]
 // CHECK-X64-NEXT:    ret i32 [[DATA]]
 //
 int test_outp(unsigned short port, int data) {
@@ -84,13 +84,13 @@ int test_outp(unsigned short port, int data) {
 // CHECK-I386-LABEL: define dso_local noundef zeroext i16 @test_outpw(
 // CHECK-I386-SAME: i16 noundef zeroext [[PORT:%.*]], i16 noundef returned zeroext [[DATA:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // CHECK-I386-NEXT:  [[ENTRY:.*:]]
-// CHECK-I386-NEXT:    tail call void asm sideeffect "outw ${0:w}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i16 [[DATA]], i16 [[PORT]]) #[[ATTR3]], !srcloc [[META5:![0-9]+]]
+// CHECK-I386-NEXT:    tail call void asm sideeffect "outw ${0:w}, ${1:w}", "{ax},N{dx},~{dirflag},~{fpsr},~{flags}"(i16 [[DATA]], i16 [[PORT]]) #[[ATTR3]], !srcloc [[META5:![0-9]+]]
 // CHECK-I386-NEXT:    ret i16 [[DATA]]
 //
 // CHECK-X64-LABEL: define dso_local noundef i16 @test_outpw(
 // CHECK-X64-SAME: i16 noundef [[PORT:%.*]], i16 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // CHECK-X64-NEXT:  [[ENTRY:.*:]]
-// CHECK-X64-NEXT:    tail call void asm sideeffect "outw ${0:w}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i16 [[DATA]], i16 [[PORT]]) #[[ATTR5]], !srcloc [[META4:![0-9]+]]
+// CHECK-X64-NEXT:    tail call void asm sideeffect "outw ${0:w}, ${1:w}", "{ax},N{dx},~{dirflag},~{fpsr},~{flags}"(i16 [[DATA]], i16 [[PORT]]) #[[ATTR5]], !srcloc [[META4:![0-9]+]]
 // CHECK-X64-NEXT:    ret i16 [[DATA]]
 //
 unsigned short test_outpw(unsigned short port, unsigned short data) {
@@ -101,13 +101,13 @@ unsigned short test_outpw(unsigned short port, unsigned short data) {
 // CHECK-I386-LABEL: define dso_local noundef i32 @test_outpd(
 // CHECK-I386-SAME: i16 noundef zeroext [[PORT:%.*]], i32 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // CHECK-I386-NEXT:  [[ENTRY:.*:]]
-// CHECK-I386-NEXT:    tail call void asm sideeffect "outl ${0:k}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR3]], !srcloc [[META6:![0-9]+]]
+// CHECK-I386-NEXT:    tail call void asm sideeffect "outl ${0:k}, ${1:w}", "{ax},N{dx},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR3]], !srcloc [[META6:![0-9]+]]
 // CHECK-I386-NEXT:    ret i32 [[DATA]]
 //
 // CHECK-X64-LABEL: define dso_local noundef i32 @test_outpd(
 // CHECK-X64-SAME: i16 noundef [[PORT:%.*]], i32 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // CHECK-X64-NEXT:  [[ENTRY:.*:]]
-// CHECK-X64-NEXT:    tail call void asm sideeffect "outl ${0:k}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR5]], !srcloc [[META5:![0-9]+]]
+// CHECK-X64-NEXT:    tail call void asm sideeffect "outl ${0:k}, ${1:w}", "{ax},N{dx},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR5]], !srcloc [[META5:![0-9]+]]
 // CHECK-X64-NEXT:    ret i32 [[DATA]]
 //
 unsigned long test_outpd(unsigned short port, unsigned long data) {
@@ -118,13 +118,13 @@ unsigned long test_outpd(unsigned short port, unsigned long data) {
 // CHECK-I386-LABEL: define dso_local noundef i32 @test_outp2(
 // CHECK-I386-SAME: i16 noundef zeroext [[PORT:%.*]], i32 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // CHECK-I386-NEXT:  [[ENTRY:.*:]]
-// CHECK-I386-NEXT:    tail call void asm sideeffect "outb ${0:b}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR3]], !srcloc [[META4]]
+// CHECK-I386-NEXT:    tail call void asm sideeffect "outb ${0:b}, ${1:w}", "{ax},N{dx},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR3]], !srcloc [[META4]]
 // CHECK-I386-NEXT:    ret i32 [[DATA]]
 //
 // CHECK-X64-LABEL: define dso_local noundef i32 @test_outp2(
 // CHECK-X64-SAME: i16 noundef [[PORT:%.*]], i32 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // CHECK-X64-NEXT:  [[ENTRY:.*:]]
-// CHECK-X64-NEXT:    tail call void asm sideeffect "outb ${0:b}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR5]], !srcloc [[META3]]
+// CHECK-X64-NEXT:    tail call void asm sideeffect "outb ${0:b}, ${1:w}", "{ax},N{dx},~{dirflag},~{fpsr},~{flags}"(i32 [[DATA]], i16 [[PORT]]) #[[ATTR5]], !srcloc [[META3]]
 // CHECK-X64-NEXT:    ret i32 [[DATA]]
 //
 int test_outp2(unsigned short port, int data) {
@@ -135,13 +135,13 @@ int test_outp2(unsigned short port, int data) {
 // CHECK-I386-LABEL: define dso_local noundef zeroext i16 @test_outpw2(
 // CHECK-I386-SAME: i16 noundef zeroext [[PORT:%.*]], i16 noundef returned zeroext [[DATA:%.*]]) local_unnamed_addr #[[ATTR2]] {
 // CHECK-I386-NEXT:  [[ENTRY:.*:]]
-// CHECK-I386-NEXT:    tail call void asm sideeffect "outw ${0:w}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i16 [[DATA]], i16 [[PORT]]) #[[ATTR3]], !srcloc [[META5]]
+// CHECK-I386-NEXT:    tail call void asm sideeffect "outw ${0:w}, ${1:w}", "{ax},N{dx},~{dirflag},~{fpsr},~{flags}"(i16 [[DATA]], i16 [[PORT]]) #[[ATTR3]], !srcloc [[META5]]
 // CHECK-I386-NEXT:    ret i16 [[DATA]]
 //
 // CHECK-X64-LABEL: define dso_local noundef i16 @test_outpw2(
 // CHECK-X64-SAME: i16 noundef [[PORT:%.*]], i16 noundef returned [[DATA:%.*]]) local_unnamed_addr #[[ATTR1]] {
 // CHECK-X64-NEXT:  [[ENTRY:.*:]]
-// CHECK-X64-NEXT:    tail call void asm sideeffect "outw ${0:w}, ${1:w}", "{ax},N{dx},~{memory},~{dirflag},~{fpsr},~{flags}"(i16 [[DATA]], i16 [[PORT]]) #[[ATTR5]], !srcloc [[META4]]
+// CHECK-X64-NEXT:    tail call void asm sideeffect "outw ${0:w}, ${1:w}", "{ax},N{dx},~{dirflag},~{fpsr},~{flags}"(i16 [[DATA]], i16 [[PORT]]) #[[ATTR5]], !srcloc [[META4]]
 // CHECK-X64-NEXT:    ret i16 [[DATA]]
 //
 unsigned short test_outpw2(unsigned short port, unsigned short data) {



More information about the cfe-commits mailing list