1
1
use either:: { Either , Either :: { Left , Right } } ;
2
2
use llvm_sys:: core:: { LLVMGetAlignment , LLVMSetAlignment , LLVMGetInstructionOpcode , LLVMIsTailCall , LLVMGetPreviousInstruction , LLVMGetNextInstruction , LLVMGetInstructionParent , LLVMInstructionEraseFromParent , LLVMInstructionClone , LLVMSetVolatile , LLVMGetVolatile , LLVMGetNumOperands , LLVMGetOperand , LLVMGetOperandUse , LLVMSetOperand , LLVMValueAsBasicBlock , LLVMIsABasicBlock , LLVMGetICmpPredicate , LLVMGetFCmpPredicate , LLVMIsAAllocaInst , LLVMIsALoadInst , LLVMIsAStoreInst } ;
3
+ #[ llvm_versions( 3.8 ..=latest) ]
4
+ use llvm_sys:: core:: { LLVMGetOrdering , LLVMSetOrdering } ;
3
5
#[ llvm_versions( 3.9 ..=latest) ]
4
6
use llvm_sys:: core:: LLVMInstructionRemoveFromParent ;
5
7
use llvm_sys:: LLVMOpcode ;
@@ -8,7 +10,7 @@ use llvm_sys::prelude::LLVMValueRef;
8
10
use crate :: basic_block:: BasicBlock ;
9
11
use crate :: values:: traits:: AsValueRef ;
10
12
use crate :: values:: { BasicValue , BasicValueEnum , BasicValueUse , Value } ;
11
- use crate :: { IntPredicate , FloatPredicate } ;
13
+ use crate :: { AtomicOrdering , IntPredicate , FloatPredicate } ;
12
14
13
15
// REVIEW: Split up into structs for SubTypes on InstructionValues?
14
16
// REVIEW: This should maybe be split up into InstructionOpcode and ConstOpcode?
@@ -98,6 +100,16 @@ pub struct InstructionValue {
98
100
}
99
101
100
102
impl InstructionValue {
103
+ fn is_a_load_inst ( & self ) -> bool {
104
+ !unsafe { LLVMIsALoadInst ( self . as_value_ref ( ) ) } . is_null ( )
105
+ }
106
+ fn is_a_store_inst ( & self ) -> bool {
107
+ !unsafe { LLVMIsAStoreInst ( self . as_value_ref ( ) ) } . is_null ( )
108
+ }
109
+ fn is_a_alloca_inst ( & self ) -> bool {
110
+ !unsafe { LLVMIsAAllocaInst ( self . as_value_ref ( ) ) } . is_null ( )
111
+ }
112
+
101
113
pub ( crate ) fn new ( instruction_value : LLVMValueRef ) -> Self {
102
114
debug_assert ! ( !instruction_value. is_null( ) ) ;
103
115
@@ -185,45 +197,32 @@ impl InstructionValue {
185
197
// SubTypes: Only apply to memory access instructions
186
198
/// Returns whether or not a memory access instruction is volatile.
187
199
pub fn get_volatile ( & self ) -> Result < bool , & ' static str > {
188
- let value_ref = self . as_value_ref ( ) ;
189
- unsafe {
190
- // Although cmpxchg and atomicrmw can have volatile, LLVM's C API
191
- // does not export that functionality.
192
- if LLVMIsALoadInst ( value_ref) . is_null ( ) &&
193
- LLVMIsAStoreInst ( value_ref) . is_null ( ) {
194
- return Err ( "Value is not a load or store." ) ;
195
- }
196
- Ok ( LLVMGetVolatile ( value_ref) == 1 )
200
+ // Although cmpxchg and atomicrmw can have volatile, LLVM's C API
201
+ // does not export that functionality.
202
+ if !self . is_a_load_inst ( ) && !self . is_a_store_inst ( ) {
203
+ return Err ( "Value is not a load or store." ) ;
197
204
}
205
+ Ok ( unsafe { LLVMGetVolatile ( self . as_value_ref ( ) ) } == 1 )
198
206
}
199
207
200
208
// SubTypes: Only apply to memory access instructions
201
209
/// Sets whether or not a memory access instruction is volatile.
202
210
pub fn set_volatile ( & self , volatile : bool ) -> Result < ( ) , & ' static str > {
203
- let value_ref = self . as_value_ref ( ) ;
204
- unsafe {
205
- // Although cmpxchg and atomicrmw can have volatile, LLVM's C API
206
- // does not export that functionality.
207
- if LLVMIsALoadInst ( value_ref) . is_null ( ) &&
208
- LLVMIsAStoreInst ( value_ref) . is_null ( ) {
209
- return Err ( "Value is not a load or store." ) ;
210
- }
211
- Ok ( LLVMSetVolatile ( value_ref, volatile as i32 ) )
211
+ // Although cmpxchg and atomicrmw can have volatile, LLVM's C API
212
+ // does not export that functionality.
213
+ if !self . is_a_load_inst ( ) && !self . is_a_store_inst ( ) {
214
+ return Err ( "Value is not a load or store." ) ;
212
215
}
216
+ Ok ( unsafe { LLVMSetVolatile ( self . as_value_ref ( ) , volatile as i32 ) } )
213
217
}
214
218
215
219
// SubTypes: Only apply to memory access and alloca instructions
216
220
/// Returns alignment on a memory access instruction or alloca.
217
221
pub fn get_alignment ( & self ) -> Result < u32 , & ' static str > {
218
- let value_ref = self . as_value_ref ( ) ;
219
- unsafe {
220
- if LLVMIsAAllocaInst ( value_ref) . is_null ( ) &&
221
- LLVMIsALoadInst ( value_ref) . is_null ( ) &&
222
- LLVMIsAStoreInst ( value_ref) . is_null ( ) {
223
- return Err ( "Value is not an alloca, load or store." ) ;
224
- }
225
- Ok ( LLVMGetAlignment ( value_ref) )
222
+ if !self . is_a_alloca_inst ( ) && !self . is_a_load_inst ( ) && !self . is_a_store_inst ( ) {
223
+ return Err ( "Value is not an alloca, load or store." ) ;
226
224
}
225
+ Ok ( unsafe { LLVMGetAlignment ( self . as_value_ref ( ) ) } )
227
226
}
228
227
229
228
// SubTypes: Only apply to memory access and alloca instructions
@@ -232,15 +231,42 @@ impl InstructionValue {
232
231
if !alignment. is_power_of_two ( ) && alignment != 0 {
233
232
return Err ( "Alignment is not a power of 2!" ) ;
234
233
}
235
- let value_ref = self . as_value_ref ( ) ;
236
- unsafe {
237
- if LLVMIsAAllocaInst ( value_ref) . is_null ( ) &&
238
- LLVMIsALoadInst ( value_ref) . is_null ( ) &&
239
- LLVMIsAStoreInst ( value_ref) . is_null ( ) {
240
- return Err ( "Value is not an alloca, load or store." ) ;
241
- }
242
- Ok ( LLVMSetAlignment ( value_ref, alignment) )
234
+ if !self . is_a_alloca_inst ( ) && !self . is_a_load_inst ( ) && !self . is_a_store_inst ( ) {
235
+ return Err ( "Value is not an alloca, load or store." ) ;
243
236
}
237
+ Ok ( unsafe { LLVMSetAlignment ( self . as_value_ref ( ) , alignment) } )
238
+ }
239
+
240
+ // SubTypes: Only apply to memory access instructions
241
+ /// Returns atomic ordering on a memory access instruction.
242
+ #[ llvm_versions( 3.8 ..=latest) ]
243
+ pub fn get_atomic_ordering ( & self ) -> Result < AtomicOrdering , & ' static str > {
244
+ if !self . is_a_load_inst ( ) && !self . is_a_store_inst ( ) {
245
+ return Err ( "Value is not a load or store." ) ;
246
+ }
247
+ Ok ( unsafe { LLVMGetOrdering ( self . as_value_ref ( ) ) } . into ( ) )
248
+ }
249
+
250
+ // SubTypes: Only apply to memory access instructions
251
+ /// Sets atomic ordering on a memory access instruction.
252
+ #[ llvm_versions( 3.8 ..=latest) ]
253
+ pub fn set_atomic_ordering ( & self , ordering : AtomicOrdering ) -> Result < ( ) , & ' static str > {
254
+ // Although fence and atomicrmw both have an ordering, the LLVM C API
255
+ // does not support them. The cmpxchg instruction has two orderings and
256
+ // does not work with this API.
257
+ if !self . is_a_load_inst ( ) && !self . is_a_store_inst ( ) {
258
+ return Err ( "Value is not a load or store instruction." ) ;
259
+ }
260
+ match ordering {
261
+ AtomicOrdering :: Release if self . is_a_load_inst ( ) =>
262
+ return Err ( "The release ordering is not valid on load instructions." ) ,
263
+ AtomicOrdering :: AcquireRelease =>
264
+ return Err ( "The acq_rel ordering is not valid on load or store instructions." ) ,
265
+ AtomicOrdering :: Acquire if self . is_a_store_inst ( ) =>
266
+ return Err ( "The acquire ordering is not valid on store instructions." ) ,
267
+ _ => { } ,
268
+ } ;
269
+ Ok ( unsafe { LLVMSetOrdering ( self . as_value_ref ( ) , ordering. into ( ) ) } )
244
270
}
245
271
246
272
/// Obtains the number of operands an `InstructionValue` has.
0 commit comments