Skip to content

Commit 7cec687

Browse files
committed
[AArch64] Add support for the __{inc|add}x18{byte|word|dword|qword intrinsics
1 parent b0ca543 commit 7cec687

File tree

4 files changed

+235
-17
lines changed

4 files changed

+235
-17
lines changed

clang/include/clang/Basic/BuiltinsAArch64.def

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,16 @@ TARGET_HEADER_BUILTIN(__readx18word, "UsUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES,
281281
TARGET_HEADER_BUILTIN(__readx18dword, "UNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
282282
TARGET_HEADER_BUILTIN(__readx18qword, "ULLiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
283283

284+
TARGET_HEADER_BUILTIN(__addx18byte, "vUNiUc", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
285+
TARGET_HEADER_BUILTIN(__addx18word, "vUNiUs", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
286+
TARGET_HEADER_BUILTIN(__addx18dword, "vUNiUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
287+
TARGET_HEADER_BUILTIN(__addx18qword, "vUNiULLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
288+
289+
TARGET_HEADER_BUILTIN(__incx18byte, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
290+
TARGET_HEADER_BUILTIN(__incx18word, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
291+
TARGET_HEADER_BUILTIN(__incx18dword, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
292+
TARGET_HEADER_BUILTIN(__incx18qword, "vUNi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
293+
284294
TARGET_HEADER_BUILTIN(_CopyDoubleFromInt64, "dSLLi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
285295
TARGET_HEADER_BUILTIN(_CopyFloatFromInt32, "fSi", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")
286296
TARGET_HEADER_BUILTIN(_CopyInt32FromFloat, "Sif", "nh", INTRIN_H, ALL_MS_LANGUAGES, "")

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,19 @@ static Value *handleAsDoubleBuiltin(CodeGenFunction &CGF, const CallExpr *E) {
244244
return CGF.Builder.CreateBitCast(BitVec, ResultType);
245245
}
246246

247+
/// Helper for the read/write/add/inc X18 builtins: read the X18 register and
248+
/// return it as an i8 pointer.
249+
Value *readX18AsPtr(CodeGenFunction &CGF) {
250+
LLVMContext &Context = CGF.CGM.getLLVMContext();
251+
llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "x18")};
252+
llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
253+
llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
254+
llvm::Function *F =
255+
CGF.CGM.getIntrinsic(llvm::Intrinsic::read_register, {CGF.Int64Ty});
256+
llvm::Value *X18 = CGF.Builder.CreateCall(F, Metadata);
257+
return CGF.Builder.CreateIntToPtr(X18, CGF.Int8PtrTy);
258+
}
259+
247260
/// getBuiltinLibFunction - Given a builtin id for a function like
248261
/// "__builtin_fabsf", return a Function* for "fabsf".
249262
llvm::Constant *CodeGenModule::getBuiltinLibFunction(const FunctionDecl *FD,
@@ -11821,14 +11834,7 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
1182111834
BuiltinID == AArch64::BI__writex18dword ||
1182211835
BuiltinID == AArch64::BI__writex18qword) {
1182311836
// Read x18 as i8*
11824-
LLVMContext &Context = CGM.getLLVMContext();
11825-
llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "x18")};
11826-
llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
11827-
llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
11828-
llvm::Function *F =
11829-
CGM.getIntrinsic(llvm::Intrinsic::read_register, {Int64Ty});
11830-
llvm::Value *X18 = Builder.CreateCall(F, Metadata);
11831-
X18 = Builder.CreateIntToPtr(X18, Int8PtrTy);
11837+
llvm::Value *X18 = readX18AsPtr(*this);
1183211838

1183311839
// Store val at x18 + offset
1183411840
Value *Offset = Builder.CreateZExt(EmitScalarExpr(E->getArg(0)), Int64Ty);
@@ -11842,23 +11848,67 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
1184211848
BuiltinID == AArch64::BI__readx18word ||
1184311849
BuiltinID == AArch64::BI__readx18dword ||
1184411850
BuiltinID == AArch64::BI__readx18qword) {
11851+
// Read x18 as i8*
11852+
llvm::Value *X18 = readX18AsPtr(*this);
11853+
11854+
// Load x18 + offset
11855+
Value *Offset = Builder.CreateZExt(EmitScalarExpr(E->getArg(0)), Int64Ty);
11856+
Value *Ptr = Builder.CreateGEP(Int8Ty, X18, Offset);
1184511857
llvm::Type *IntTy = ConvertType(E->getType());
11858+
LoadInst *Load = Builder.CreateAlignedLoad(IntTy, Ptr, CharUnits::One());
11859+
return Load;
11860+
}
11861+
11862+
if (BuiltinID == AArch64::BI__addx18byte ||
11863+
BuiltinID == AArch64::BI__addx18word ||
11864+
BuiltinID == AArch64::BI__addx18dword ||
11865+
BuiltinID == AArch64::BI__addx18qword ||
11866+
BuiltinID == AArch64::BI__incx18byte ||
11867+
BuiltinID == AArch64::BI__incx18word ||
11868+
BuiltinID == AArch64::BI__incx18dword ||
11869+
BuiltinID == AArch64::BI__incx18qword) {
11870+
llvm::Type *IntTy;
11871+
bool isIncrement;
11872+
switch (BuiltinID) {
11873+
case AArch64::BI__incx18byte:
11874+
IntTy = Int8Ty;
11875+
isIncrement = true;
11876+
break;
11877+
case AArch64::BI__incx18word:
11878+
IntTy = Int16Ty;
11879+
isIncrement = true;
11880+
break;
11881+
case AArch64::BI__incx18dword:
11882+
IntTy = Int32Ty;
11883+
isIncrement = true;
11884+
break;
11885+
case AArch64::BI__incx18qword:
11886+
IntTy = Int64Ty;
11887+
isIncrement = true;
11888+
break;
11889+
default:
11890+
IntTy = ConvertType(E->getArg(1)->getType());
11891+
isIncrement = false;
11892+
break;
11893+
}
1184611894

1184711895
// Read x18 as i8*
11848-
LLVMContext &Context = CGM.getLLVMContext();
11849-
llvm::Metadata *Ops[] = {llvm::MDString::get(Context, "x18")};
11850-
llvm::MDNode *RegName = llvm::MDNode::get(Context, Ops);
11851-
llvm::Value *Metadata = llvm::MetadataAsValue::get(Context, RegName);
11852-
llvm::Function *F =
11853-
CGM.getIntrinsic(llvm::Intrinsic::read_register, {Int64Ty});
11854-
llvm::Value *X18 = Builder.CreateCall(F, Metadata);
11855-
X18 = Builder.CreateIntToPtr(X18, Int8PtrTy);
11896+
llvm::Value *X18 = readX18AsPtr(*this);
1185611897

1185711898
// Load x18 + offset
1185811899
Value *Offset = Builder.CreateZExt(EmitScalarExpr(E->getArg(0)), Int64Ty);
1185911900
Value *Ptr = Builder.CreateGEP(Int8Ty, X18, Offset);
1186011901
LoadInst *Load = Builder.CreateAlignedLoad(IntTy, Ptr, CharUnits::One());
11861-
return Load;
11902+
11903+
// Add values
11904+
Value *ValToAdd =
11905+
isIncrement ? ConstantInt::get(IntTy, 1) : EmitScalarExpr(E->getArg(1));
11906+
Value *AddResult = Builder.CreateAdd(Load, ValToAdd);
11907+
11908+
// Store val at x18 + offset
11909+
StoreInst *Store =
11910+
Builder.CreateAlignedStore(AddResult, Ptr, CharUnits::One());
11911+
return Store;
1186211912
}
1186311913

1186411914
if (BuiltinID == AArch64::BI_CopyDoubleFromInt64 ||

clang/lib/Headers/intrin.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,16 @@ unsigned short __readx18word(unsigned long offset);
396396
unsigned long __readx18dword(unsigned long offset);
397397
unsigned __int64 __readx18qword(unsigned long offset);
398398

399+
void __addx18byte(unsigned long offset, unsigned char data);
400+
void __addx18word(unsigned long offset, unsigned short data);
401+
void __addx18dword(unsigned long offset, unsigned long data);
402+
void __addx18qword(unsigned long offset, unsigned __int64 data);
403+
404+
void __incx18byte(unsigned long offset);
405+
void __incx18word(unsigned long offset);
406+
void __incx18dword(unsigned long offset);
407+
void __incx18qword(unsigned long offset);
408+
399409
double _CopyDoubleFromInt64(__int64);
400410
float _CopyFloatFromInt32(__int32);
401411
__int32 _CopyInt32FromFloat(float);

clang/test/CodeGen/arm64-microsoft-intrinsics.c

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,154 @@ unsigned __int64 check__readx18qword(unsigned LONG offset) {
288288
// CHECK-MSCOMPAT: %[[RETVAL:.*]] = load i64, ptr %[[PTR]], align 1
289289
// CHECK-MSCOMPAT: ret i64 %[[RETVAL]]
290290

291+
#ifdef __LP64__
292+
void check__addx18byte(unsigned char data, unsigned LONG offset) {
293+
#else
294+
void check__addx18byte(unsigned LONG offset, unsigned char data) {
295+
#endif
296+
__addx18byte(offset, data);
297+
}
298+
299+
// CHECK-MSCOMPAT: %[[DATA_ADDR:.*]] = alloca i8, align 1
300+
// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
301+
// CHECK-MSCOMPAT: store i8 %data, ptr %[[DATA_ADDR]], align 1
302+
// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
303+
// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
304+
// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
305+
// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
306+
// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
307+
// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
308+
// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i8, ptr %[[PTR]], align 1
309+
// CHECK-MSCOMPAT: %[[DATA:.*]] = load i8, ptr %[[DATA_ADDR]], align 1
310+
// CHECK-MSCOMPAT: %[[SUM:.*]] = add i8 %[[ORIG_VAL]], %[[DATA]]
311+
// CHECK-MSCOMPAT: store i8 %[[SUM]], ptr %[[PTR]], align 1
312+
313+
#ifdef __LP64__
314+
void check__addx18word(unsigned short data, unsigned LONG offset) {
315+
#else
316+
void check__addx18word(unsigned LONG offset, unsigned short data) {
317+
#endif
318+
__addx18word(offset, data);
319+
}
320+
321+
// CHECK-MSCOMPAT: %[[DATA_ADDR:.*]] = alloca i16, align 2
322+
// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
323+
// CHECK-MSCOMPAT: store i16 %data, ptr %[[DATA_ADDR]], align 2
324+
// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
325+
// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
326+
// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
327+
// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
328+
// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
329+
// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
330+
// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i16, ptr %[[PTR]], align 1
331+
// CHECK-MSCOMPAT: %[[DATA:.*]] = load i16, ptr %[[DATA_ADDR]], align 2
332+
// CHECK-MSCOMPAT: %[[SUM:.*]] = add i16 %[[ORIG_VAL]], %[[DATA]]
333+
// CHECK-MSCOMPAT: store i16 %[[SUM]], ptr %[[PTR]], align 1
334+
335+
#ifdef __LP64__
336+
void check__addx18dword(unsigned LONG data, unsigned LONG offset) {
337+
#else
338+
void check__addx18dword(unsigned LONG offset, unsigned LONG data) {
339+
#endif
340+
__addx18dword(offset, data);
341+
}
342+
343+
// CHECK-MSCOMPAT: %[[DATA_ADDR:.*]] = alloca i32, align 4
344+
// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
345+
// CHECK-MSCOMPAT: store i32 %data, ptr %[[DATA_ADDR]], align 4
346+
// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
347+
// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
348+
// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
349+
// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
350+
// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
351+
// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
352+
// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i32, ptr %[[PTR]], align 1
353+
// CHECK-MSCOMPAT: %[[DATA:.*]] = load i32, ptr %[[DATA_ADDR]], align 4
354+
// CHECK-MSCOMPAT: %[[SUM:.*]] = add i32 %[[ORIG_VAL]], %[[DATA]]
355+
// CHECK-MSCOMPAT: store i32 %[[SUM]], ptr %[[PTR]], align 1
356+
357+
#ifdef __LP64__
358+
void check__addx18qword(unsigned __int64 data, unsigned LONG offset) {
359+
#else
360+
void check__addx18qword(unsigned LONG offset, unsigned __int64 data) {
361+
#endif
362+
__addx18qword(offset, data);
363+
}
364+
365+
// CHECK-MSCOMPAT: %[[DATA_ADDR:.*]] = alloca i64, align 8
366+
// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
367+
// CHECK-MSCOMPAT: store i64 %data, ptr %[[DATA_ADDR]], align 8
368+
// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
369+
// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
370+
// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
371+
// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
372+
// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
373+
// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
374+
// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i64, ptr %[[PTR]], align 1
375+
// CHECK-MSCOMPAT: %[[DATA:.*]] = load i64, ptr %[[DATA_ADDR]], align 8
376+
// CHECK-MSCOMPAT: %[[SUM:.*]] = add i64 %[[ORIG_VAL]], %[[DATA]]
377+
// CHECK-MSCOMPAT: store i64 %[[SUM]], ptr %[[PTR]], align 1
378+
379+
void check__incx18byte(unsigned LONG offset) {
380+
__incx18byte(offset);
381+
}
382+
383+
// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
384+
// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
385+
// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
386+
// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
387+
// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
388+
// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
389+
// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
390+
// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i8, ptr %[[PTR]], align 1
391+
// CHECK-MSCOMPAT: %[[SUM:.*]] = add i8 %[[ORIG_VAL]], 1
392+
// CHECK-MSCOMPAT: store i8 %[[SUM]], ptr %[[PTR]], align 1
393+
394+
void check__incx18word(unsigned LONG offset) {
395+
__incx18word(offset);
396+
}
397+
398+
// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
399+
// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
400+
// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
401+
// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
402+
// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
403+
// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
404+
// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
405+
// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i16, ptr %[[PTR]], align 1
406+
// CHECK-MSCOMPAT: %[[SUM:.*]] = add i16 %[[ORIG_VAL]], 1
407+
// CHECK-MSCOMPAT: store i16 %[[SUM]], ptr %[[PTR]], align 1
408+
409+
void check__incx18dword(unsigned LONG offset) {
410+
__incx18dword(offset);
411+
}
412+
413+
// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
414+
// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
415+
// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
416+
// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
417+
// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
418+
// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
419+
// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
420+
// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i32, ptr %[[PTR]], align 1
421+
// CHECK-MSCOMPAT: %[[SUM:.*]] = add i32 %[[ORIG_VAL]], 1
422+
// CHECK-MSCOMPAT: store i32 %[[SUM]], ptr %[[PTR]], align 1
423+
424+
void check__incx18qword(unsigned LONG offset) {
425+
__incx18qword(offset);
426+
}
427+
428+
// CHECK-MSCOMPAT: %[[OFFSET_ADDR:.*]] = alloca i32, align 4
429+
// CHECK-MSCOMPAT: store i32 %offset, ptr %[[OFFSET_ADDR]], align 4
430+
// CHECK-MSCOMPAT: %[[X18:.*]] = call i64 @llvm.read_register.i64(metadata ![[MD2]])
431+
// CHECK-MSCOMPAT: %[[X18_AS_PTR:.*]] = inttoptr i64 %[[X18]] to ptr
432+
// CHECK-MSCOMPAT: %[[OFFSET:.*]] = load i32, ptr %[[OFFSET_ADDR]], align 4
433+
// CHECK-MSCOMPAT: %[[ZEXT_OFFSET:.*]] = zext i32 %[[OFFSET]] to i64
434+
// CHECK-MSCOMPAT: %[[PTR:.*]] = getelementptr i8, ptr %[[X18_AS_PTR]], i64 %[[ZEXT_OFFSET]]
435+
// CHECK-MSCOMPAT: %[[ORIG_VAL:.*]] = load i64, ptr %[[PTR]], align 1
436+
// CHECK-MSCOMPAT: %[[SUM:.*]] = add i64 %[[ORIG_VAL]], 1
437+
// CHECK-MSCOMPAT: store i64 %[[SUM]], ptr %[[PTR]], align 1
438+
291439
double check__CopyDoubleFromInt64(__int64 arg1) {
292440
return _CopyDoubleFromInt64(arg1);
293441
}

0 commit comments

Comments
 (0)